В форме выдержать сравнение
BeginInvoke (new Action (() => {
MessageBox.Show ());
}));
с
Invoke (new Action (() => {
MessageBox.Show ());
}));
Каково различие, и когда я должен использовать один по другому? Как поведение затронуто насосом сообщения MessageBox?
Я сделал некоторое тестирование и нашел, что оба метода блокируют UI.
Единственная разница, это Вызывает, на самом деле назван немедленно, в то время как BeginInvoke занимает (очень короткое) время, пока код не выполняется. Это должно ожидаться.
BeginInvoke
вызовет делегат асинхронно, возвращаясь немедленно, поставив делегат в очередь на выполнение независимо от текущего потока.
Invoke
вызовет делегата синхронно, блокируя вызывающий поток до завершения работы делегата.
Чтобы увидеть разницу, попробуйте следующий код:
BeginInvoke(new Action(()=>Console.WriteLine("BeginInvoke")));
Console.WriteLine("AfterBeginInvokeCalled");
Invoke(new Action(()=>Console.WriteLine("Invoke")));
Console.WriteLine("AfterInvokeCalled");
Вы должны увидеть вывод, похожий на следующий, где текст "BeginInvoke" отложен из-за его асинхронного выполнения:
AfterBeginInvokeCalled
Invoke
AfterInvokeCalled
BeginInvoke
Что касается наблюдаемого вами поведения, поскольку синхронным или асинхронным является только акт вызова делегата; содержимое метода вполне может привести к остановке вызывающего потока или блокировке пользовательского интерфейса. В случае показа окна сообщения, независимо от того, отложен ли делегат с помощью BeginInvoke
или нет, после вызова делегата пользовательский интерфейс будет заблокирован до тех пор, пока окно сообщения не будет удалено.
На самом деле Саймон не ошибся.
BeginInvoke
подобен отправке сообщения в поток пользовательского интерфейса со словами: «Сделайте это, как только представится возможность».
Invoke
- это как сказать: «Сделайте это прямо сейчас . Я подожду ».
Уточнение: только то, что вы говорите потоку пользовательского интерфейса:« Сделайте это прямо сейчас », это не означает, что вы являетесь Богом потока пользовательского интерфейса и можете заставить его бросить все, что он делает. По сути, ключевые слова в приведенном выше утверждении - «Я буду ждать».
Дело в том, что в вашем примере кода сообщение, которое вы отправляете потоку пользовательского интерфейса, выглядит следующим образом: call MessageBox.Show
. Угадай, что? В любом случае это заблокирует поток пользовательского интерфейса.
Если вы хотите заметить асинхронное поведение BeginInvoke
, вызовите его из отдельного потока, поместите точку останова после вызова BeginInvoke
в своем коде и обратите внимание, что точка останова получает нажмите, даже когда отображается окно сообщения (и пользовательский интерфейс заблокирован). Если вы вызовете Invoke
, код не будет продолжаться, пока пользователь не закроет окно сообщения.
BeginInvoke является асинхронным... это означает, что вызывающий поток не будет ждать возвращения вызванного метода.
Итак, диалоговое окно всегда замораживает GUI. Но разница между begin invoke и invoke теперь должна быть ясна:
Invoke ждет возвращения вызванного метода. BeginInvoke этого не делает.
Для MessageBox.Show вопрос в основном неуместен.
Единственное отличие состоит в том, что с BeginInvoke сам вызывающий поток не будет блокироваться, поэтому он может продолжать выполнять какие-то действия (очистку, дальнейшую обработку и т. Д.).
Очевидно, что поток пользовательского интерфейса будет заблокирован, потому что появилось модальное окно, ожидающее ввода пользователя, чтобы закрыть его.
Хотя большинство ответов технически верны, они не задают очевидного вопроса.
Почему вы вообще хотите заключать вызовы MessageBox () в Invoke / BeginOnvoke?
Как объяснил Джефф, использование BeginInvoke или Invoke в этой ситуации просто бесполезно.
Похоже, вы запутались между использованием Invoke / BeginInvoke в форме / элементе управления Windows в многопоточной ситуации и использованием Invoke / BeginInvoke в экземпляре делегата (то есть в модели асинхронного программирования).
Это легко сделать, поскольку имена явно идентичны, однако сценарии их использования и их поведение различаются.
Книга CLR Via C # дает хорошее объяснение обоих типов Invoke / BeginInvoke.