Подтвердить что ты не робот

Многопоточное обслуживание, BackgroundWorker vs ThreadPool?

У меня есть служба Windows.NET 3.5. Я тестирую небольшое приложение, которое просто спит в потоках после их запуска, для случайных временных интервалов от 300 до 6500 мс. У меня есть различные вопросы по этой проблеме.

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

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

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

4b9b3361

Ответ 1

Значение в BackgroundWorker заключается в том, что он может вызывать события ProgressChanged и RunworkerCompleted в потоке, создавшем его экземпляр. Это делает его очень удобным в программах, которые не поддерживают бесплатную многопоточность.

Для того, чтобы это работало правильно, необходимо, чтобы свойство SynchronizationContext.Current ссылалось на поставщика синхронизации не по умолчанию. Поставщик, который отвечает за маршалинг вызовов из одного потока в другой. Платформа .NET имеет двух доступных поставщиков: System.Windows.Forms.WindowsFormsSynchronizationContext и System.Windows.Threading.DispatcherSynchronizationContext. Эти провайдеры обрабатывают синхронизацию соответственно для Winforms и WPF.

Там соединение, Winforms и WPF - обе библиотеки классов, которые имеют проблему с многопоточностью. Оба реализуют графические интерфейсы пользователя и графические пользовательские интерфейсы на основе Windows, в основном поточно-ориентированные. Окна Windows могут быть обновлены только из потока, который их создал. Другими словами, эти пользовательские поставщики синхронизации существуют, потому что они крайне необходимы. Также следует отметить, что они работают, используя преимущества работы потоков пользовательского интерфейса. Поток пользовательского интерфейса выполняет код, управляемый событиями, прокачивая цикл сообщений для получения уведомлений. Поставщик синхронизации может внедрять вызовы в обработчики событий, используя этот механизм. Это не случайно.

Возвращаясь к теме, служба Windows не имеет такой возможности. Он не имеет графического интерфейса и не устанавливает пользовательский поставщик синхронизации. Таким образом, BackgroundWorker не предоставляет функции, полезной в сервисе. Без пользовательского поставщика синхронизации поставщик по умолчанию просто запускает события в потоке потоков. Что бесполезно, вы также можете запустить событие из вашего рабочего потока. Получить события для запуска в другом конкретном потоке очень трудно, если только вы не воссоздаете механизм цикла сообщений или не подключаетесь к соединению Winforms и не создаете смоделированный поток пользовательского интерфейса, используя невидимое окно. Что не является чем-то необычным, кстати.

Ответ 2

BackgroundWorker был разработан для упрощения взаимодействия задачи, работающей в фоновом потоке с пользовательским интерфейсом. Вы увидите отличный ответ о том, когда использовать BackGroundWorker, ThreadPool и просто Thread на BackgroundWorker vs background Thread

Я думаю, что он отвечает на вопрос:).

Ответ 3

Я написал довольно подробный обзор различных реализаций асинхронных фоновых задач в моем блоге. Сводка: предпочитает Task; вторым выбором будет BackgroundWorker; и используйте только Thread или ThreadPool.QueueUserWorkItem, если вам действительно нужно.

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

Чтобы ответить на ваши конкретные вопросы:

BackgroundWorker работает на любом хосте, включая WinForms и WPF (и даже ASP.NET!), потому что основан на SynchronizationContext. У служб Windows нет SynchronizationContext, но вы можете использовать ActionThread из Nito.Async library, которая поставляется с SynchronizationContext.

Если я правильно прочитал ваш вопрос, у вас есть Thread и рассматривают ThreadPool и BackgroundWorker. Из этих вариантов я рекомендую BackgroundWorker, но если у вас есть такая возможность, используйте новый класс Task в .NET 4.0 (если вы устанавливаете Microsoft Rx, вы также можете использовать Task в .NET 3.5).

Ответ 4

Определенно не Backgroundworker для службы

Вы должны пойти с задачами в пространстве имен System.Threading.Tasks, также могут использовать задачи Параллельное выполнение потоков

http://msdn.microsoft.com/en-us/library/dd460717.aspx
Я цитирую: "Начиная с .NET Framework 4, TPL является предпочтительным способом написания многопоточного и параллельного кода".

Некоторые показания:
http://msdn.microsoft.com/en-us/library/dd997413%28VS.100%29.aspx

Начать здесь:
http://msmvps.com/blogs/brunoboucard/archive/2010/04/09/parallel-programming-task-oriented-parallel-part-1.aspx
http://msmvps.com/blogs/brunoboucard/archive/2010/05/18/parallel-programming-in-c-4-0-task-oriented-parallel-programming-part-2.aspx
http://msmvps.com/blogs/brunoboucard/archive/2010/11/06/parallel-programming-with-c-4-0-part-3.aspx

Другие примеры
http://www.dotnetcurry.com/ShowArticle.aspx?ID=489
http://www.dotnetfunda.com/articles/article984-parallel-compting-in-csharp-40-.aspx

Ответ 5

Я думаю, что ваш третий выбор лучше. Я сделал аналогичные вещи с службами Windows в .Net 3.5 и обнаружил, что создание моих собственных потоков было хорошим способом, особенно с потоками, которые взаимодействовали с веб-службами.

Я создаю рабочий экземпляр и передаю ему обратный вызов, который сигнализирует услугу, когда это будет сделано. Я сохраняю готовые потоки в Queue и очищаю их в соответствии с максимальным количеством совпадающих потоков, которые я хочу. Если вас интересует только количество запущенных сервисов, вы можете отслеживать их с помощью простого счетчика. Я предпочитаю хранить каждый экземпляр рабочего экземпляра в Dictionary с ключом по потоку ManagedThreadId, чтобы я мог легко сигнализировать каждый экземпляр, если я хочу закрыть его чисто. Это также удобно для опроса запущенных экземпляров для проверки состояния.