В чем разница между Invoke() и BeginInvoke()

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

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

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

6 ответов


значит делегировать.Invoke / BeginInvoke или Control.Вызова/Метод BeginInvoke?

  • делегат.Вызова: выполняется синхронно, в одном потоке.
  • делегат.BeginInvoke: выполняется асинхронно в потоке threadpool.
  • управление.Invoke: выполняется в потоке пользовательского интерфейса, но вызывающий поток ожидает завершения перед продолжением.
  • управление.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";

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

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


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

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

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

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


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

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

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


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

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) звонок.


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

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

статья MSDN


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

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

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

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

см. Pro WPF в главе c# 31