2008-10-23 3 views
335

Просто интересно, какая разница между BeginInvoke() и Invoke()?В чем разница между Invoke() и BeginInvoke()

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

EDIT: В чем разница между созданием объекта Threading и вызовом invoke на нем и просто вызовом BeginInvoke() на делегат? или они одно и то же?

ответ

486

Вы имеете в виду Delegate.Invoke/BeginInvoke или Control.Invoke/BeginInvoke?

  • Delegate.Invoke: Выполняется синхронно, в той же теме.
  • Делегат.BeginInvoke: Выполняется асинхронно, в потоке threadpool.
  • Control.Invoke: Выполняется в потоке пользовательского интерфейса, но вызов продолжается до завершения.
  • Control.BeginInvoke: Выполняется в потоке пользовательского интерфейса, а вызывающий поток не ждет завершения.

Ответ Тима упоминается, когда вы, возможно, захотите использовать BeginInvoke - хотя это было в основном связано с делегатом.BeginInvoke, я подозреваю.

Для приложений Windows Forms я бы предположил, что вы должны обычно использовать BeginInvoke. Таким образом, вам не нужно беспокоиться о тупике, например, но вам нужно понять, что пользовательский интерфейс, возможно, не был обновлен к тому времени, когда вы его посмотрите на него! В частности, вы не должны изменять данные, которые может использоваться для отображения в пользовательском интерфейсе. Например, если у вас есть человек с FirstName и LastName свойствами, и вы сделали:

person.FirstName = "Kevin"; // person is a shared reference 
person.LastName = "Spacey"; 
control.BeginInvoke(UpdateName); 
person.FirstName = "Keyser"; 
person.LastName = "Soze"; 

то интерфейс может хорошо закончить показ «Кайзер Спейси». (Есть вероятность, что он может отобразить «Кевин Соз», но только через странность модели памяти.)

Если у вас есть такая проблема, однако Control.BeginInvoke легче получить право и будет избегать ваших фоновый поток от необходимости ждать веской причины. Обратите внимание, что команда Windows Forms гарантировала, что вы можете использовать Control.BeginInvoke в режиме «огонь и забухание», т. Е. Без вызова EndInvoke. Это не относится к асинхронным вызовам вообще: обычно каждый BeginXXX должен иметь соответствующий вызов EndXXX, обычно в обратном вызове.

+3

Тогда зачем использовать ppl Invoke over BeingInvoke? Не должно быть преимуществ перед использованием Invoke. Оба выполняют процессы в фоновом режиме, только один из них находится в одном потоке, а другой - в другом потоке? – yeeen 2010-10-08 09:23:19

8

Делегат.BeginInvoke() асинхронно ставит в очередь вызов делегата и немедленно возвращает управление. При использовании Delegate.BeginInvoke() вы должны вызвать метод Delegate.EndInvoke() в методе обратного вызова, чтобы получить результаты.

Делегат.Invoke() синхронно вызывает делегата в том же потоке.

MSDN Article

41

Опираясь на ответ Jon тарелочкам, есть моменты, когда вы хотите вызвать делегат и ждать его исполнения, чтобы завершить до текущего потока продолжается. В этих случаях вызов Invoke - это то, что вы хотите.

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

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

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

21

Разница между Control.Invoke() и Control.BeginInvoke() есть

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

логический вывод о том, что делегат вы передаете Invoke() может иметь вне параметров или возвращаемого значения, в то время как делегат вы передаете BeginInvoke() не может (вы должны использовать EndInvoke для получения результатов).

14

Просто чтобы дать короткий рабочий пример, чтобы увидеть эффект их разности

new Thread(foo).Start(); 

private void foo() 
{ 
    this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, 
    (ThreadStart)delegate() 
    { 
     myTextBox.Text = "bing"; 
     Thread.Sleep(TimeSpan.FromSeconds(3)); 
    }); 
    MessageBox.Show("done"); 
} 

Если использование BeginInvoke, MessageBox выскакивает одновременно с текстом обновления. Если используется Invoke, MessageBox появляется после 3 секундного сна. Следовательно, показано влияние асинхронного (BeginInvoke) и синхронного вызова (Invoke).

6

Просто добавьте, почему и когда использовать Invoke().

И Invoke(), и BeginInvoke() маршалируют код, указанный вами в потоке диспетчера.

Но в отличие от BeginInvoke(), Invoke() останавливает ваш поток, пока диспетчер не выполнит ваш код. Возможно, вы захотите использовать Invoke(), если вам нужно приостановить асинхронную операцию, пока пользователь не предоставит некоторую обратную связь.

Например, вы можете вызвать Invoke() для запуска фрагмента кода, который показывает диалоговое окно OK/Cancel. После того, как пользователь нажмет кнопку и ваш маршалированный код завершится, метод invoke() вернется, и вы сможете действовать в ответ пользователя.

См. Раздел Pro WPF в главе C# 31

Смежные вопросы