Invoke() 和 BeginInvoke() 有什么区别?
本文关键字:区别 什么 BeginInvoke Invoke | 更新日期: 2023-09-27 17:48:52
只是想知道BeginInvoke()
和Invoke()
有什么区别?
主要是每个将用于什么。
编辑:创建线程对象并调用 invoke 与仅在委托上调用 BeginInvoke()
有什么区别? 还是它们是一回事?
你的意思是Delegate.Invoke
/BeginInvoke
还是Control.Invoke
/BeginInvoke
?
-
Delegate.Invoke
:在同一线程上同步执行。 -
Delegate.BeginInvoke
:在threadpool
线程上异步执行。 -
Control.Invoke
:在 UI 线程上执行,但调用线程等待完成后再继续。 -
Control.BeginInvoke
:在 UI 线程上执行,调用线程不等待完成。
蒂姆的回答提到了你可能什么时候想使用BeginInvoke
——尽管它主要是针对Delegate.BeginInvoke
的,我怀疑。
对于 Windows 窗体应用程序,我建议您通常应该使用 BeginInvoke
。例如,这样你就不需要担心死锁 - 但您需要了解,在您下次查看它时,UI 可能尚未更新!特别是,不应修改 UI 线程可能将用于显示目的的数据。例如,如果您有一个具有 FirstName
和 LastName
属性的Person
,并且您执行了:
person.FirstName = "Kevin"; // person is a shared reference
person.LastName = "Spacey";
control.BeginInvoke(UpdateName);
person.FirstName = "Keyser";
person.LastName = "Soze";
然后UI很可能最终显示"Keyser Spacey"。(它有可能显示"Kevin Soze",但只能通过记忆模型的怪异
。但是,除非您遇到此类问题,否则Control.BeginInvoke
更容易正确处理,并且可以避免您的后台线程无缘无故地等待。请注意,Windows 窗体团队已保证您可以以"即发即弃"的方式使用Control.BeginInvoke
- 即无需调用EndInvoke
。一般来说,异步调用并非如此:通常每个 BeginXXX 都应该有一个相应的 EndXXX 调用,通常在回调中。
基于Jon Skeet的回复,有时您希望调用委托并等待其执行完成,然后再继续当前线程。 在这些情况下,调用调用是您想要的。
在多线程应用程序中,您可能不希望线程等待委托完成执行,尤其是在该委托执行 I/O 时(这可能会使委托和线程阻塞(。
在这些情况下,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,则消息框会在文本更新的同时弹出。如果使用调用,消息框将在 3 秒睡眠后弹出。因此,显示异步(BeginInvoke(和同步(Invoke(调用的效果。
Delegate.BeginInvoke(( 异步排队委托的调用并立即返回控制权。 使用 Delegate.BeginInvoke(( 时,应在回调方法中调用 Delegate.EndInvoke(( 来获取结果。
Delegate.Invoke(( 在同一线程中同步调用委托。
MSDN 文章
只需添加为什么以及何时使用 Invoke((。
Invoke(( 和 BeginInvoke(( 都将您指定的代码封送到调度程序线程。
但与 BeginInvoke(( 不同的是,Invoke(( 会停止你的线程,直到调度程序执行你的代码。如果需要暂停异步操作,直到用户提供某种反馈,则可能需要使用 Invoke((。
例如,可以调用 Invoke(( 来运行显示"确定/取消"对话框的代码片段。用户单击按钮并且封送代码完成后,invoke(( 方法将返回,您可以根据用户的响应进行操作。
请参阅 C# 中的 Pro WPF 第 31 章