none
Как лучше всего реализовать очереди? C# (Аналоги потоков C#). RRS feed

  • Вопрос

  • Доброго времени суток.

    У себя в проекте я использовал потоки.

    Т.е запускаются потоки, и по очереди выполняются, после выполнения каждого потока идёт ожидание(сутки к примеру) и так до бесконечности.

    void Readout(object ThermalEquipment)
    {
    	do
    	{
    		System.Threading.Monitor.Enter(this);
    		//..
    		System.Threading.Monitor.Exit(this);
    		
            Thread.Sleep(3600000 * 24 / 1);
    	}
    	while (true);
    }
    

    Изначально меня всё устраивало, но потом:

    Мне понадобилось останавливать и убивать потоки а потом создавать и запускать их же снова.

    С этой задачей я справился, но когда количество потоков выросло (~500 к примеру), то запуск и особенно остановка начала занимать время.

    Посоветуйте пожалуйста какие-нибудь алгоритмы очередей. 

    Создание элементов, выполнение по очереди, ожидание, гибкость и чтобы форма не подвисала.



    27 марта 2014 г. 9:09

Ответы

  • А зачем потоку сутки висеть? Добавляя опрос запишите в переменную время добавления.

    В одном единственном таймере раз в минуту (или секунду если принципиально) проверяйте не наступило ли время опроса и инициируйте опрос в потоке.

    Массив переменных всяко меньше ресурсов съест чем куча простаивающих потоков.


    VB.Net - WPF, WinRT, WP

    • Помечено в качестве ответа ivanich274 27 марта 2014 г. 11:01
    27 марта 2014 г. 9:42
    Отвечающий
  • На каждый поток выделяется по умолчанию 1 Мегабайт памяти (виртуальной). 500 потоков - полгигабайта.

    Даже если поток спит, диспетчер ОС периодически переключается на него (потому что диспетчер не знает о внутренней логике кода в этом потоке). Каждое переключение - это выгрузка контекста одного потока и загрузка контекста другого потока. Поэтому даже если все потоки спят - при таком их колечестве ОС усиленно работает, выгружая-загружая контексты.

    Как уже предложил LXGDARK, достаточно одного таймера. По событию таймера запускаем задачу опроса оборудования. Это может быть либо Task, либо поток из пула - ThreadPool.QueueUserWorkItem.

    Дополню.

    В зависимости от того, какой тип приложения используется (вернее, нужен ли доступ к ГУЮ из потока), можно использовать разные типы таймеров. Если взять System.Threading.Timer, то колбэк будет и так запускаться в отдельном потоке, взятом из пула - то есть вручную создавать новый поток не надо.

    Если нужна возможность отмены, причём даже в том случае, если опрос оборудования ещё не начался, лучше взять Task - в этом классе всё продумано, легко и удобно использовать CancellationToken.

    • Изменено Petalvik 27 марта 2014 г. 10:17
    • Помечено в качестве ответа ivanich274 27 марта 2014 г. 11:01
    27 марта 2014 г. 10:07

Все ответы

  • Не совсем понятно зачем вы это делаете. Все потоке в момент Sleep висят в памяти и понятное дело когда их много это вызывает проблемы производительности.

    Решение в вашем случае явно в пересмотре алгоритма, но на что его поменять можно сказать, поняв что и зачем вы делаете.


    VB.Net - WPF, WinRT, WP

    • Предложено в качестве ответа Petalvik 27 марта 2014 г. 10:03
    • Отменено предложение в качестве ответа Petalvik 27 марта 2014 г. 10:04
    27 марта 2014 г. 9:31
    Отвечающий
  • Не совсем понятно зачем вы это делаете. Все потоке в момент Sleep висят в памяти и понятное дело когда их много это вызывает проблемы производительности.

    Решение в вашем случае явно в пересмотре алгоритма, но на что его поменять можно сказать, поняв что и зачем вы делаете.


    VB.Net - WPF, WinRT, WP

    Я раз в сутки опрашиваю оборудование. 

    Запустил программу, запустил опрос и программа раз в сутки выполняет опрос, пока я не остановлю опрос.

    P.S в некоторых случаях у меня Sleep не сутки, а например час, если оборудование не опросилось с 1 попытки.

    как то так


    • Изменено ivanich274 27 марта 2014 г. 9:37
    27 марта 2014 г. 9:35
  • А зачем потоку сутки висеть? Добавляя опрос запишите в переменную время добавления.

    В одном единственном таймере раз в минуту (или секунду если принципиально) проверяйте не наступило ли время опроса и инициируйте опрос в потоке.

    Массив переменных всяко меньше ресурсов съест чем куча простаивающих потоков.


    VB.Net - WPF, WinRT, WP

    • Помечено в качестве ответа ivanich274 27 марта 2014 г. 11:01
    27 марта 2014 г. 9:42
    Отвечающий
  • А зачем потоку сутки висеть? Добавляя опрос запишите в переменную время добавления.

    В одном единственном таймере раз в минуту (или секунду если принципиально) проверяйте не наступило ли время опроса и инициируйте опрос в потоке.

    Массив переменных всяко меньше ресурсов съест чем куча простаивающих потоков.


    VB.Net - WPF, WinRT, WP

    Вы предлагаете запускать поток, после окончания работы потока убивать его а потом через сутки снова запускать?верно?

    Я клоню к другому.

    Проблема в том, что если сразу запустить 500 потоков, а потом передумать и остановить их - это уже затраты времени пользователя,я имею ввиду, что не запустил и забыл, а запустил а потом передумал и нажал остановить, поэтому я хочу уйти от потоков.

    А мне надо чтобы по нажатию кнопки была быстрая реакция остановки и запуска опроса. А при убивании потоков в таком количестве быстро не получается. 

    P.S Если только при запуске опроса сразу не все потоки запускать а по одному по готовности.. 

    • Изменено ivanich274 27 марта 2014 г. 9:58
    27 марта 2014 г. 9:51
  • На каждый поток выделяется по умолчанию 1 Мегабайт памяти (виртуальной). 500 потоков - полгигабайта.

    Даже если поток спит, диспетчер ОС периодически переключается на него (потому что диспетчер не знает о внутренней логике кода в этом потоке). Каждое переключение - это выгрузка контекста одного потока и загрузка контекста другого потока. Поэтому даже если все потоки спят - при таком их колечестве ОС усиленно работает, выгружая-загружая контексты.

    Как уже предложил LXGDARK, достаточно одного таймера. По событию таймера запускаем задачу опроса оборудования. Это может быть либо Task, либо поток из пула - ThreadPool.QueueUserWorkItem.

    Дополню.

    В зависимости от того, какой тип приложения используется (вернее, нужен ли доступ к ГУЮ из потока), можно использовать разные типы таймеров. Если взять System.Threading.Timer, то колбэк будет и так запускаться в отдельном потоке, взятом из пула - то есть вручную создавать новый поток не надо.

    Если нужна возможность отмены, причём даже в том случае, если опрос оборудования ещё не начался, лучше взять Task - в этом классе всё продумано, легко и удобно использовать CancellationToken.

    • Изменено Petalvik 27 марта 2014 г. 10:17
    • Помечено в качестве ответа ivanich274 27 марта 2014 г. 11:01
    27 марта 2014 г. 10:07
  • Простите дилетанта.

    Правильно ли я понимаю, по таймеру запускать Task?

    Объясните пожалуйста на примере небольшом, если не сложно.

    Мне видимо подойдёт второй случай, с возможностью отмены.


    27 марта 2014 г. 10:58