BackgroundWorker против фонового потока
у меня есть стилистический вопрос о выборе реализации фонового потока, который я должен использовать в приложении windows form. В настоящее время у меня есть BackgroundWorker на форме, которая имеет бесконечное (while(true)) петли. В этом цикле я использую WaitHandle.WaitAny чтобы поток дремал, пока не произойдет что-то интересное. Один из дескрипторов событий, которые я жду, - это"StopThread" мероприятие, так что я могу вырваться из петли. Это событие сигнализируется, когда от моего переопределенного Form.Dispose().
Я где-то читал, что BackgroundWorker is действительно предназначен для операций, которые вы не хотите связывать с пользовательским интерфейсом и иметь конечный конец - например, загрузка файла или обработка последовательности элементов. В данном случае "конец" неизвестен и только тогда, когда окно закрыто. Поэтому было бы более уместно для меня использовать фоновый поток вместо BackgroundWorker для этой цели?
11 ответов:
из моего понимания вашего вопроса, Вы используете
BackgroundWorkerкак стандартный поток.Почему
BackgroundWorkerрекомендуется для вещей, которые вы не хотите связывать поток пользовательского интерфейса, потому что он предоставляет некоторые приятные события при разработке Win Forms.событий, как
RunWorkerCompletedсигнал, когда поток завершил то, что ему нужно сделать, иProgressChangedсобытие для обновления графического интерфейса в ходе выполнения потоков.если вы не используя их, я не вижу никакого вреда в использовании стандартного потока для того, что вам нужно сделать.
некоторые из моих мыслей...
- использовать BackgroundWorker если у вас есть одна задача, которая выполняется в фоновом режиме и должен взаимодействовать с UI. Задача маршалинга данных и вызовов методов в поток пользовательского интерфейса обрабатывается автоматически через его модель на основе событий. Избегайте BackgroundWorker, если...
- ваша сборка не имеет или не напрямую взаимодействовать с UI,
- вам нужно, чтобы поток был потоком переднего плана, или
- вам нужно манипулировать приоритетом потока.
- использовать ThreadPool поток, когда требуется эффективность. Пул потоков помогает избежать накладных расходов, связанных с созданием, запуском и остановкой потоков. Избегайте использования пула потоков, если...
- задача выполняется в течение времени жизни приложения
- вам нужно, чтобы поток был на переднем плане потока,
- вам нужно манипулировать приоритетом потока, или
- вам нужно, чтобы поток имел фиксированную идентичность (прерывание, приостановка, обнаружение).
- использовать Thread класс для длительных задач и когда вам требуются функции, предлагаемые формальной моделью потока, например, выбор между передним и фоновым потоками, настройка приоритета потока, мелкозернистый контроль над выполнением потока и т. д.
в значительной степени то, что сказал Мэтт Дэвис, со следующими дополнительными пунктами:
для меня главный дифференциатор с
BackgroundWorker- это автоматическая сортировка завершенного события черезSynchronizationContext. В контексте пользовательского интерфейса это означает, что завершенное событие срабатывает в потоке пользовательского интерфейса и поэтому может использоваться для обновления пользовательского интерфейса. Это важный дифференциатор, если вы используетеBackgroundWorkerв контексте пользовательского интерфейса.задачи, выполняемые с помощью
ThreadPoolне может быть легко отменен (это включает в себяThreadPool.QueueUserWorkItemи делегаты выполняют асинхронно). Поэтому, хотя это позволяет избежать накладных расходов на раскрутку потока, если вам нужна отмена, либо используйтеBackgroundWorkerили (скорее за пределами пользовательского интерфейса) раскрутите поток и сохраните ссылку на него, чтобы вы могли вызватьAbort().
кроме того, вы связываете поток threadpool для жизни фонового рабочего, что может представлять интерес, поскольку их существует только конечное число. Я бы сказал, что если вы только когда-либо создаете поток один раз для своего приложения (и не используете ни одну из функций background worker), то используйте поток, а не поток backgroundworker/threadpool.
вы знаете, иногда просто легче работать с BackgroundWorker независимо от того, используете ли Вы Windows Forms, WPF или любую другую технологию. Аккуратная часть об этих парнях - вы получаете резьбу, не беспокоясь слишком много о том, где вы выполняете поток, что отлично подходит для простых задач.
до
BackgroundWorkerрассмотрим сначала, если вы хотите отменить поток (закрытие приложения, отмена пользователя), то вам нужно решить, если ваш поток должен проверить аннулирование или если оно должно быть навязано самому исполнению.
BackgroundWorker.CancelAsync()устанавливаетсяCancellationPendingдоtrueно больше ничего не будет делать, тогда ответственность за потоки будет постоянно проверять это, имейте в виду также, что вы можете получить состояние гонки в этом подходе, когда ваш пользователь отменен, но поток завершен до тестирования дляCancellationPending.
Thread.Abort()С другой стороны будет бросать исключение в рамках выполнения потока, который обеспечивает отмена этого потока, вы должны быть осторожны о том, что может быть опасно, если это исключение внезапно возникло в ходе выполнения, хотя.резьба требует очень тщательного рассмотрения независимо от того, какая задача, для дальнейшего чтения:
параллельное программирование в .NET Framework Управляемые Потоковые Рекомендации
Я знал, как использовать потоки, прежде чем я знал .NET, поэтому потребовалось некоторое привыкание, когда я начал использовать BackgroundWorkers. Мэтт Дэвис суммировал разницу с большим совершенством, но я бы добавил, что труднее понять, что именно делает код, и это может затруднить отладку. Легче думать о создании и закрытии потоков, ИМО, чем о том, чтобы дать работу пулу потоков.
Я до сих пор не могу комментировать чужие сообщения, так что простите мою кратковременную хромоту в использовании ответа на адрес piers7
Не используйте поток.Abort (); вместо этого, сигнализируйте о событии и создайте свой поток, чтобы он заканчивался изящно при сигнале. Нитка.Abort () вызывает ThreadAbortException в произвольной точке выполнения потока, который может делать все виды несчастных вещей, таких как сиротские мониторы, поврежденное общее состояние и т. д. http://msdn.microsoft.com/en-us/library/system.threading.thread.abort.aspx
Если он не сломался - исправьте его, пока он не будет...просто шучу:)
но серьезно BackgroundWorker, вероятно, очень похож на то, что у вас уже есть, если бы вы начали с него с самого начала, возможно, вы бы сэкономили некоторое время - но на данный момент я не вижу необходимости. Если что-то не работает, или вы думаете, что ваш текущий код трудно понять, то я бы придерживался того, что у вас есть.
основное отличие состоит в том, как вы заявили, генерации событий GUI из
BackgroundWorker. Если потоку не нужно обновлять отображение или генерировать события для основного потока GUI, то это может быть простой поток.
фоновый рабочий-это класс, который работает в отдельном потоке, но он предоставляет дополнительные функции, которые вы не получаете с помощью простого потока (например, обработка отчета о ходе выполнения задачи).
Если вам не нужны дополнительные функции, предоставленные фоновым работником, - и кажется, что вы этого не делаете, - тогда поток будет более подходящим.
Я хочу указать на одно поведение класса BackgroundWorker, которое еще не упоминалось. Вы можете сделать обычный поток для запуска в фоновом режиме, установив поток.Свойство 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 использует поток, который работает в фоновом режиме.
что меня озадачивает, так это то, что конструктор visual studio позволяет использовать только BackgroundWorkers и таймеры, которые фактически не работают с проектом службы.
Это дает вам аккуратное перетаскивание элементов управления на ваш сервис, но... даже не пытайтесь развернуть его. Не получится.
услуги: Используйте только систему.Таймеры.Таймер Система.Окна.Формы.Таймер не будет работать, даже если он доступен в toolbox
услуги: Фоновые рабочие не будут работать, когда он работает как служба использование системы.Нарезка резьбы.ThreadPools вместо этого или асинхронные вызовы
Comments