Какая разница между Invoke() и BeginInvoke()

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

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

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

Ответ 1

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

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

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

В приложениях Windows Forms я бы предположил, что вы обычно должны использовать BeginInvoke. Таким образом, вам не нужно беспокоиться о тупике, например, но вам нужно понять, что пользовательский интерфейс, возможно, не был обновлен к тому времени, когда вы его посмотрите на него! В частности, вы не должны изменять данные, которые может использоваться для отображения в пользовательском интерфейсе. Например, если у вас есть свойства Person with 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, обычно в обратном вызове.

Ответ 2

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

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

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

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

Ответ 3

Разница между Control.Invoke() и Control.BeginInvoke() равна

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

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

Ответ 4

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

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 появляется одновременно с текстовым обновлением. Если используется Вызывать, MessageBox появляется после 3-секундного сна. Следовательно, показывается эффект асинхронного (BeginInvoke) и синхронный вызов ( Invoke).

Ответ 5

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

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

Статья MSDN

Ответ 6

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

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

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

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

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