BackgroundWorker vs background Thread

У меня есть стилистический вопрос о выборе реализации фонового потока, который я должен использовать в приложении формы Windows. В настоящее время у меня есть BackgroundWorker в форме, которая имеет бесконечный цикл (while(true)). В этом цикле я использую WaitHandle.WaitAny, чтобы поддерживать зависание потока, пока не произойдет что-то интересное. Одна из обработок событий, которые я жду, - это событие "StopThread", чтобы я мог выйти из цикла. Это событие сигнализируется, когда из моего переопределенного Form.Dispose().

Я где-то читал, что BackgroundWorker действительно предназначен для операций, которые вы не хотите связывать с пользовательским интерфейсом и иметь конечный конец - например, загрузку файла или обработку последовательности элементов. В этом случае "конец" неизвестен и только когда окно закрыто. Поэтому для меня было бы более целесообразным использовать для этой цели фоновый поток вместо BackgroundWorker?

Ответ 1

Из моего понимания вашего вопроса вы используете BackgroundWorker как стандартный поток.

Причина, по которой BackgroundWorker рекомендуется для вещей, которые вы не хотите связывать с потоком пользовательского интерфейса, состоит в том, что при разработке Win Forms он предоставляет интересные события.

События, такие как RunWorkerCompleted, чтобы сообщить, когда поток завершил то, что ему нужно было сделать, и событие ProgressChanged, чтобы обновить графический интерфейс для выполнения потоков.

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

Ответ 2

Некоторые из моих мыслей...

  • Используйте BackgroundWorker, если у вас есть одна задача, которая работает в фоновом режиме и должна взаимодействовать с пользовательским интерфейсом. Задача сортировки запросов данных и методов к потоку пользовательского интерфейса обрабатывается автоматически через его основанную на события модель. Избегайте BackgroundWorker, если...
    • ваша сборка не имеет или не взаимодействует напрямую с пользовательским интерфейсом,
    • вам нужно, чтобы поток был передним потоком, или
    • вам нужно управлять приоритетом потока.
  • Используйте поток ThreadPool, когда требуется эффективность. ThreadPool помогает избежать накладных расходов, связанных с созданием, запуском и остановкой потоков. Избегайте использования ThreadPool, если...
    • задача выполняется за время жизни вашего приложения,
    • вам нужно, чтобы поток был передним потоком,
    • вам нужно управлять приоритетом потока или
    • вам нужно, чтобы поток имел фиксированную идентификацию (прерывание, приостановка, обнаружение).
  • Используйте класс Thread для длительных задач и когда вам нужны функции, предлагаемые формальной моделью потоков, например, выбор между передними и фоновые потоки, настройка приоритета потока, мелкозернистый контроль выполнения потоков и т.д.

Ответ 3

В значительной степени то, что сказал Мэтт Дэвис со следующими дополнительными пунктами:

Для меня основным отличием с BackgroundWorker является автоматическое сортирование завершенного события через SynchronizationContext. В контексте пользовательского интерфейса это означает, что завершенное событие срабатывает в потоке пользовательского интерфейса, и поэтому его можно использовать для обновления интерфейса. Это основной отличительный признак, если вы используете BackgroundWorker в контексте пользовательского интерфейса.

Задачи, выполняемые с помощью ThreadPool, не могут быть легко отменены (это включает в себя ThreadPool. QueueUserWorkItem, а делегаты выполняются asyncronously). Таким образом, хотя это позволяет избежать накладных расходов на раскрутку потоков, если вам требуется аннулирование, либо используйте BackgroundWorker, либо (скорее всего, вне пользовательского интерфейса), разверните поток и сохраните ссылку на него, чтобы вы могли вызвать Abort().

Ответ 4

Также вы связываете поток потока в течение жизненного цикла рабочего стола, что может вызывать беспокойство, поскольку их только конечное число. Я бы сказал, что если вы только когда-либо создаете поток один раз для своего приложения (и не используете какие-либо функции рабочего стола), используйте поток, а не поток backgroundworker/threadpool.

Ответ 5

Вы знаете, иногда проще работать с BackgroundWorker, независимо от того, используете ли вы Windows Forms, WPF или любую другую технологию. Оптимальная часть этих парней - вы получаете потоки, не беспокоясь о том, где вы выполняете поток, что отлично подходит для простых задач.

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

BackgroundWorker.CancelAsync() установит CancellationPending в true, но не сделает ничего больше, тогда ответственность за потоки будет постоянно проверяться, помните также, что в этом подходе вы можете столкнуться с состоянием гонки ваш пользователь отменен, но поток завершен до тестирования для CancellationPending.

Thread.Abort(), с другой стороны, генерирует исключение в процессе выполнения потока, которое принудительно отменяет этот поток, вы должны быть осторожны в отношении того, что может быть опасно, если это исключение внезапно возникло в ходе выполнения.

Threading нуждается в очень тщательном рассмотрении независимо от того, какая задача, для некоторого дальнейшего чтения:

Параллельное программирование в .NET Framework Рекомендации по управляемым потокам

Ответ 6

Я знал, как использовать потоки, прежде чем я узнал .NET, поэтому мне пришлось привыкнуть, когда я начал использовать BackgroundWorkers. Мэтт Дэвис обобщил разницу с большим превосходством, но я бы добавил, что сложнее понять, что именно делает код, и это может усложнить отладку. Легче думать о создании и отключении потоков, IMO, чем думать о предоставлении работы пулу потоков.

Я до сих пор не могу комментировать сообщения других людей, поэтому прощайте мою сиюминутную хромоту в использовании ответа на адрес piers7

Не используйте Thread.Abort(); вместо этого, сигнализировать событие и проектировать ваш поток, чтобы закончить изящно, когда сигнализировали. Thread.Abort() вызывает исключение ThreadAbortException в произвольной точке выполнения потока, которое может выполнять все виды несчастливых вещей, таких как мониторы-сироты, поврежденное разделяемое состояние и т.д. http://msdn.microsoft.com/en-us/library/system.threading.thread.abort.aspx

Ответ 7

Если он не сломался - исправьте его до тех пор, пока он... просто шутит:)

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

Ответ 8

Основное отличие состоит, как вы заявили, в создании событий GUI из BackgroundWorker. Если нить не нуждается в обновлении дисплея или генерации событий для основного потока GUI, тогда это может быть простой поток.

Ответ 9

Фоновый работник - это класс, который работает в отдельном потоке, но он предоставляет дополнительные функции, которые вы не получаете с помощью простого потока (например, обработки отчета о выполнении задачи).

Если вам не нужны дополнительные функции, данные фоновым работником - и, похоже, вы этого не сделали - тогда был бы более подходящим Thread.

Ответ 10

Я хочу указать одно поведение класса BackgroundWorker, о котором еще не упоминалось. Вы можете сделать обычный поток, который будет выполняться в фоновом режиме, установив свойство Thread.IsBackground.

Фоновые потоки идентичны потокам переднего плана, за исключением того, что фоновые потоки не препятствуют завершению процесса. [1]

Вы можете проверить это поведение, вызвав следующий метод в конструкторе окна формы.

void TestBackgroundThread()
{
    var thread = new Thread((ThreadStart)delegate()
    {
        long count = 0;
        while (true)
        {
            count++;
            Debug.WriteLine("Thread loop count: " + count);
        }
    });

    // Choose one option:
    thread.IsBackground = false; // <--- This will make the thread run in background
    thread.IsBackground = true; // <--- This will delay program termination

    thread.Start();
}

Когда для свойства IsBackground установлено значение true и вы закроете окно, ваше приложение завершит нормальную работу.

Но когда для свойства IsBackground установлено значение false (по умолчанию), и вы закрываете окно, тогда просто окно исчезнет, ​​но процесс все равно будет продолжать работать.

В классе BackgroundWorker используется поток, который работает в фоновом режиме.

Ответ 11

Какое недоумение для меня заключается в том, что дизайнер визуальной студии позволяет вам использовать BackgroundWorkers и Timers, которые фактически не работают с проектом службы.

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

Услуги: Используйте только System.Timers.Timer System.Windows.Forms.Timer не будет работать, даже если он доступен в панели инструментов

Услуги: BackgroundWorkers не будут работать, когда он работает как служба Используйте System.Threading.ThreadPools вместо или Async вызывает