想知道 BeginInvoke()
和 Invoke()
之间有什么区别?
主要是它们各自的用途。
编辑:创建线程对象并在其上调用invoke与只在委托上调用 BeginInvoke()
之间有什么区别?还是它们是一样的?
想知道 BeginInvoke()
和 Invoke()
之间有什么区别?
主要是它们各自的用途。
编辑:创建线程对象并在其上调用invoke与只在委托上调用 BeginInvoke()
之间有什么区别?还是它们是一样的?
Delegate.Invoke
/BeginInvoke
还是 Control.Invoke
/BeginInvoke
?
Delegate.Invoke
: 在同一线程上同步执行。Delegate.BeginInvoke
: 在一个线程池线程上异步执行。Control.Invoke
: 在UI线程上执行,但调用线程会在继续之前等待完成。Control.BeginInvoke
: 在UI线程上执行,且调用线程不等待完成。Tim's 的回答提到了你何时可能想使用 BeginInvoke
,尽管它大多数是针对 Delegate.BeginInvoke
的,我猜测。
对于 Windows Forms 应用程序,我建议通常应该使用 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 Forms团队保证您可以以“fire and forget”的方式使用Control.BeginInvoke
,即不必调用EndInvoke
。这并非对于所有异步调用都适用:通常每个BeginXXX都应该有一个相应的EndXXX调用,通常在回调中执行。
基于Jon Skeet的回答,有时候你希望调用一个委托并等待它执行完之后当前线程再继续。在这种情况下,你需要使用Invoke方法。
在多线程应用程序中,你可能不希望一个线程等待委托执行完毕,特别是当委托执行I/O操作时(这可能会导致委托和线程阻塞)。
在这种情况下,使用BeginInvoke方法会很有用。通过调用该方法,你告诉委托开始执行,同时你的线程可以自由地进行其他并行任务。
虽然使用BeginInvoke会增加代码的复杂性,但是在某些情况下,其改善性能的优势是值得付出复杂性代价的。
Control.Invoke()
和 Control.BeginInvoke()
的区别在于,
BeginInvoke()
会在 GUI 线程上安排异步操作。当异步操作被安排后,您的代码将继续执行。一段时间之后(您不知道确切的时间),您的异步操作将被执行。Invoke()
将在 GUI 线程上执行您的异步操作并等待直到操作完成。一个逻辑结论是,您通过 Invoke()
传递的委托可以具有输出参数或返回值,而您通过 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,则消息框会同时弹出文本更新。如果使用Invoke,则消息框将在3秒的休眠后弹出。因此,显示了异步(BeginInvoke)和同步(Invoke)调用的效果。
仅解释何时和为什么使用Invoke()。
无论是Invoke()还是BeginInvoke(),都会将您指定的代码转移给调度程序线程。
但是,与BeginInvoke()不同的是,Invoke()会阻止您的线程,直到调度程序执行您的代码。如果您需要暂停异步操作,直到用户提供某种反馈,那么您可能需要使用Invoke()。例如,您可以调用Invoke()运行一小段代码,显示一个OK / Cancel对话框。在用户单击按钮并完成您的封送代码后,invoke()方法将返回,并且您可以根据用户的响应进行操作。
请参见Pro WPF in C#第31章
Delegate.BeginInvoke() 异步地将委托的调用排队,并立即返回控制。使用 Delegate.BeginInvoke() 时,应在回调方法中调用 Delegate.EndInvoke() 以获取结果。
Delegate.Invoke() 同步地在同一线程中调用委托。
ref
和out
参数都被视为相同,但在运行时是不同的。 - DhanRaj Wanjare