Чем диспетчер отличается от фонового потока?


Чем концепция диспетчера в .NET 3.5 и WPF отличается от фонового потока в .NET 2.0 ?

Например, какова будет разница между приведенными ниже утверждениями:

delegate.Invoke/BeginInvoke

И

this.dispatcher.Invoke/BeginInvoke
4 6

4 ответа:

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

Фоновый поток, в свою очередь, отличается от потока пользовательского интерфейса. Так что работать на один из этих потоков не повлияет на пользовательский интерфейс и не заблокирует его.

Понятие BeginInvoke и Invoke можно представить следующим образом.

  • BeginInvoke означает: "сделайте это и вернитесь, прежде чем это завершится. Я либо не забочусь о возврате стоимости, либо вы можете перезвонить мне по этому адресу в какой-то момент в будущем."
  • Призыв означает: "сделай это, и я буду сидеть здесь и ждать, когда это завершится."

Теперь, как это относится к диспетчерам и фоновым потокам, - совсем другой вопрос. Как говорит Джастин, диспетчер процессов очередь дел, которые нужно делать каждый раз, когда поток пользовательского интерфейса простаивает. Фоновый поток, который вызывает BeginInvoke на диспетчере, немедленно вернется, даже если диспетчер, возможно, еще не приступил к обработке. Если бы вместо этого использовался Invoke, фоновый поток блокировался бы до тех пор, пока поток пользовательского интерфейса не завершит обработку. Обратите внимание, что в Silverlight нет вызова диспетчера, и в большинстве случаев вы, вероятно, не хотите, чтобы ваш фоновый поток блокировался во время обработки потока пользовательского интерфейса работа.

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

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

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

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

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

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