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

WPF BackgroundWorker против диспетчера

В моем приложении WPF мне нужно выполнить асинхронную операцию, тогда мне нужно обновить графический интерфейс. И эта вещь, которую я должен делать много раз в разное время с различными oparations. Я знаю два способа сделать это: Диспетчер и BackgroundWorker.

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

Спасибо! Pileggi

4b9b3361

Ответ 1

Основное отличие метода Dispatcher и других потоков заключается в том, что диспетчер фактически не многопоточен. Диспетчер управляет элементами управления, которым нужен один поток для правильной работы; метод BeginInvoke диспетчера приостанавливает события для последующего выполнения (в зависимости от приоритета и т.д.), но все же в одном и том же потоке.

BackgroundWorker, с другой стороны, фактически выполняет код в то же самое время, когда он вызывается в отдельном потоке. Это также проще использовать, чем настоящие потоки, потому что он автоматически синхронизирует (по крайней мере, я думаю, что я правильно помню) с основным потоком приложения, ответственным за элементы управления и очередь сообщений (поток Dispatcher в случае WPF и Silverlight), поэтому нет необходимости использовать Dispatcher.Invoke(или Control.Invoke в WinForms) при обновлении элементов управления из фонового потока, хотя это не всегда рекомендуется.

Как сказал Рид, параллельная библиотека задач - отличный альтернативный вариант.

Изменить: дальнейшие наблюдения.

Как я уже говорил выше, диспетчер не многопоточен; это только дает иллюзию этого, потому что он запускает делегатов, которые вы передаете ему в другое время. Я бы использовал Диспетчер только тогда, когда код действительно касается только аспекта вида приложения - то есть элементов управления, страниц, окон и всего этого. И, конечно же, его основное использование фактически инициирует действия из других потоков для правильного обновления элементов управления или в нужное время (например, настройка фокуса только после того, как какой-либо элемент управления полностью отобрал/выложил его, легче всего выполнить с помощью Диспетчера, потому что в WPF рендеринг не является точно детерминированным).

BackgroundWorker может сделать многопоточный код намного проще, чем обычно; это простое понятие, которое нужно понять, и, прежде всего, (если это имеет смысл), вы можете получить от него пользовательских работников, которые могут быть специализированными классами, выполняющими одну задачу асинхронно, со свойствами, которые могут функционировать в качестве параметров, уведомления о ходе и отмены и т.д. Я всегда находил BackgroundWorker огромную помощь (кроме случаев, когда мне приходилось извлекать из нее культуру исходного потока, чтобы поддерживать локализацию правильно: P)

Самый мощный, но и сложный путь - использовать самый низкий доступный уровень, System.Threading.Thread; однако так легко получить что-то неправильно, что это не рекомендуется. Многопоточное программирование жестко, что заданное. Тем не менее, есть много хорошей информации об этом, если вы хотите понять все аспекты: эта отличная статья нашего хорошего друга Джона Скита сразу подсказывает мне (последняя страница статьи также содержит большое количество очень интересных ссылок).

В .Net 4.0 у нас есть другой вариант: Task Parallel Library. Я не работал с этим много, но из того, что я видел, он впечатляет (и PLINQ просто замечательный). Если у вас есть любопытство и ресурсы, чтобы изучить его, то то, что я бы рекомендовал (в конце концов, не стоит так много учиться).

Ответ 2

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

Если вам не нужны события прогресса, то использование ThreadPool и Dispatcher может быть проще - особенно если вы собираетесь выполнять несколько разных операций.

Если С# 4 является опцией, однако, использование параллельной библиотеки задач также является отличным вариантом. Это позволяет использовать настройки продолжения, используя текущий SynchronizationContext, который во многих случаях обеспечивает гораздо более простую и чистую модель. Подробнее см. мой пост в блоге по этому вопросу.