В чем разница между Invoke () и BeginInvoke () - PullRequest
369 голосов
/ 23 октября 2008

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

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

РЕДАКТИРОВАТЬ: В чем разница между созданием потокового объекта и вызовом invoke для этого и просто вызовом BeginInvoke() для делегата? или это одно и то же?

Ответы [ 6 ]

534 голосов
/ 23 октября 2008

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

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

В ответе Тима упоминается, когда вы, возможно, захотите использовать BeginInvoke, хотя я подозреваю, что он в основном предназначен для Delegate.BeginInvoke.

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

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

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

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

42 голосов
/ 23 октября 2008

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

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

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

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

23 голосов
/ 11 сентября 2012

Разница между Control.Invoke() и Control.BeginInvoke() составляет

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

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

14 голосов
/ 14 декабря 2012

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

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 ) вызова.

8 голосов
/ 23 октября 2008

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

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

MSDN Артикул

7 голосов
/ 06 января 2015

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

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

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

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

См. Pro WPF в главе 31 C

.
...