В чем разница между вызовом и начальным вызовом MessageBox? - PullRequest
12 голосов
/ 12 мая 2010

В форме, сравните

BeginInvoke (new Action (() => {
    MessageBox.Show ());
}));

с

Invoke (new Action (() => {
    MessageBox.Show ());
}));

В чем разница, и когда я должен использовать один над другим? Как влияет на поведение насос сообщений MessageBox?

Я провел некоторое тестирование и обнаружил, что оба метода блокируют пользовательский интерфейс.

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

Ответы [ 5 ]

16 голосов
/ 12 мая 2010

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

Invoke будет вызывать делегата синхронно, блокируя вызывающий поток, пока делегат не завершит работу.

Чтобы увидеть разницу, попробуйте следующий код:

BeginInvoke(new Action(()=>Console.WriteLine("BeginInvoke")));
Console.WriteLine("AfterBeginInvokeCalled");

Invoke(new Action(()=>Console.WriteLine("Invoke")));
Console.WriteLine("AfterInvokeCalled");

Вы должны увидеть вывод, подобный следующему, где текст «BeginInvoke» задерживается из-за его асинхронного выполнения:

AfterBeginInvokeCalled
Призовите
AfterInvokeCalled
BeginInvoke

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

14 голосов
/ 12 мая 2010

Саймон на самом деле не ошибается.

BeginInvoke - это все равно, что отправить сообщение в ветку пользовательского интерфейса и сказать: «Сделайте это, как только у вас появится возможность».

Invoke все равно что сказать: «Сделай это прямо сейчас . Я подожду».

Разъяснение: только потому, что вы говорите потоку пользовательского интерфейса: «Сделайте это прямо сейчас», это не означает, что вы являетесь Богом потока пользовательского интерфейса и можете заставить его отказаться от всего, что он делает , По сути, ключевыми словами в приведенном выше утверждении являются «Я подожду».

Дело в том, что в вашем примере кода сообщение, которое вы отправляете в поток пользовательского интерфейса: call MessageBox.Show. Угадай, что? Это в любом случае заблокирует поток пользовательского интерфейса.

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

3 голосов
/ 12 мая 2010

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

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

Invoke ожидает возврата вызванного метода BeginInvoke не.

2 голосов
/ 17 июня 2010

Хотя большинство ответов технически правильны, они не задают очевидный вопрос.

Почему вы хотите обернуть вызовы MessageBox () в Invoke / BeginOnvoke в первую очередь?

В этой ситуации просто бесполезно использовать BeginInvoke или Invoke, как объяснил Джефф.

Похоже, вы запутались между использованием Invoke / BeginInvoke в форме / элементе управления windows в многопоточной ситуации и использованием Invoke / BeginInvoke в экземпляре делегата (то есть в модели асинхронного программирования).

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

Книга CLR Via C # дает хорошее объяснение обоих типов Invoke / BeginInvoke.

1 голос
/ 12 мая 2010

Для MessageBox.Show, вопрос в основном не имеет значения.

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

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

...