.NET Thread Pool - неотзывчивый пользовательский интерфейс WinForms - PullRequest
2 голосов
/ 23 марта 2010

Сценарий

У меня есть приложение Windows Forms. Внутри основной формы есть цикл, который повторяется около 3000 раз. Создание нового экземпляра класса в новом потоке для выполнения некоторых вычислений. Принимая во внимание, что эта настройка использует пул потоков, пользовательский интерфейс остается отзывчивым, когда в цикле всего около 100 итераций (100 активов для обработки). Но как только это число начинает сильно увеличиваться, пользовательский интерфейс блокируется в режиме eggtimer, и, таким образом, журнал, который записывается в список в форме, становится нечитаемым.

Вопрос

Правильно ли я считаю, что лучший способ обойти это - использовать Background Worker? И заблокирован ли пользовательский интерфейс, потому что, хотя я использую много разных потоков (для скорости), сам интерфейс не находится в отдельном отдельном потоке?

Предлагаемые реализации высоко оценены.

EDIT !!

Итак, давайте предположим, что вместо того, чтобы просто запустить и поставить в очередь 3000 активов для обработки, я решил сделать их партиями по 100. Как бы я поступил так эффективно? Ранее я пытался добавить «Thread.Sleep (5000);» после того, как каждая партия из 100 была выпущена, но все это казалось дерьмовым ...

Ответы [ 5 ]

4 голосов
/ 23 марта 2010

Если вы создаете 3000 отдельных потоков, вы выдвигаете документированное ограничение класса ThreadPool:

Если приложение подвергается очередям деятельности, в которой большое количество задачи пула потоков ставятся в очередь, используйте Метод SetMinThreads для увеличения минимальное количество свободных потоков. В противном случае встроенная задержка в создание новых свободных потоков может привести к узкое место.

См. В этом разделе MSDN предложения по настройке пула потоков для вашей ситуации.

Если ваша работа требует значительных ресурсов процессора, то наличие такого большого количества отдельных потоков вызовет больше затрат, чем стоит. Однако, если он очень интенсивно вводит ввод-вывод, наличие большого количества потоков может несколько помочь.

.NET 4 представляет выдающуюся поддержку параллельного программирования. Если это вариант для вас, я предлагаю вам взглянуть на это .

4 голосов
/ 23 марта 2010

Больше потоков не равно максимальной скорости. На самом деле слишком много потоков равняется меньшей скорости. Если ваша задача связана только с процессором, вы должны использовать столько потоков, сколько у вас ядер, иначе вы тратите ресурсы впустую.

При 3000 итерациях и потоке формы, который пытается создать поток каждый раз, когда, вероятно, происходит то, что вы максимизируете пул потоков, и форма зависает, поскольку ей нужно дождаться завершения предыдущего потока, прежде чем он сможет выделить новый.

Очевидно, ThreadPool не работает таким образом. Я никогда не проверял это с потоками прежде, поэтому я не уверен. Другая возможность состоит в том, что задачи начинают заполнять поток пользовательского интерфейса вызовами, после чего он перестает работать в графическом интерфейсе.

1 голос
/ 23 марта 2010

Если каждый поток записывает что-то на ваш пользовательский интерфейс, каждая записанная строка журнала должна вызывать основной поток. Лучше кэшировать вывод журнала и обновлять графический интерфейс только каждые 100 итераций или что-то в этом роде.

1 голос
/ 23 марта 2010

Трудно сказать, не видя код, но, исходя из того, что вы описываете, есть один подозреваемый.

Вы упомянули, что у вас сейчас это работает на ThreadPool. Переключение на BackgroundWorker кардинально ничего не изменит, поскольку он также использует ThreadPool для выполнения. (BackgroundWorker просто упрощает вызовы ...)

При этом я подозреваю, что проблема заключается в том, что ваши уведомления возвращаются в поток пользовательского интерфейса для вашего ListBox. Если вы вызываете слишком часто, ваш пользовательский интерфейс может перестать отвечать, когда он пытается «догнать». Это может произойти, если вы передаете слишком много информации о состоянии обратно в поток пользовательского интерфейса через Control.Invoke.

В противном случае убедитесь, что ВСЕ ваша работа выполняется в ThreadPool, и вы не блокируете поток UI, и он должен работать.

0 голосов
/ 23 марта 2010

Так как я не видел ваш код, так что это всего лишь догадка с некоторыми весьма обнадеживающими догадками.

Все, что делает пул потоков - это ставит в очередь ваши запросы и затем запускает новые потоки, когда другие завершают свою работу. Теперь 3000 потоков звучат не так уж и много, но если у вас есть тонна обработки, вы можете уничтожить свой процессор.

Я не уверен, что фоновый работник поможет, так как в конечном итоге вы воссоздадите менеджера для обработки всего пула, который дает вам пул потоков. Я думаю, что больше проблем, с которыми вы сталкиваетесь, это то, что происходит слишком много данных. Я думаю, что хорошее место для начала было бы ограничить количество потоков, которые вы запускаете и поддерживаете. Менеджер пула потоков легко позволяет вам сделать это. Найдите баланс, который позволяет обрабатывать данные, сохраняя отзывчивость пользовательского интерфейса.

...