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

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

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

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

7 ответов

Решение

Вы имеете в виду 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, обычно в обратном вызове.

Основываясь на ответе Джона Скита, бывают случаи, когда вы хотите вызвать делегата и дождаться его выполнения, прежде чем текущий поток продолжится. В этих случаях вызов 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) вызовов.

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

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

Статья MSDN

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

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

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

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

Смотрите Pro WPF в C# главе 31

Заявление должно быть:-Примечание: оба ref и out параметр обрабатывается одинаково во время компиляции, но отличается во время выполнения.

Другие вопросы по тегам