Invoke()和BeginInvoke()有什么区别


398

只是想知道BeginInvoke()和之间Invoke()有什么区别?

主要是每个人的用途。

编辑:创建线程对象与调用该对象和仅调用BeginInvoke()委托之间有什么区别?还是同一件事?

Answers:


568

你是说Delegate.Invoke/ BeginInvoke还是Control.Invoke/ BeginInvoke

  • Delegate.Invoke:在同一线程上同步执行。
  • Delegate.BeginInvoke:在threadpool线程上异步执行。
  • Control.Invoke:在UI线程上执行,但是调用线程在继续之前等待完成。
  • Control.BeginInvoke:在UI线程上执行,并且调用线程不等待完成。

蒂姆(Tim)的答案提到了您可能想使用的时间BeginInvoke- Delegate.BeginInvoke我怀疑,尽管它主要是针对的。

对于Windows Forms应用程序,我建议您通常使用BeginInvoke。这样,您就不必担心死锁了-但是您需要了解,在下次查看UI时可能尚未更新UI!特别是,您不应修改UI线程可能要用于显示目的的数据。例如,如果您具有Personwith FirstNameLastName属性,并且您执行了以下操作:

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团队已保证您可以Control.BeginInvoke“一劳永逸”的方式使用-即无需致电EndInvoke。通常,异步调用不是这样:通常每个BeginXXX应该在回调中有一个对应的EndXXX调用。


4
那为什么ppl在InbeingInvoke上使用Invoke?与使用Invoke相比,应该不会有一些优势。两者都在后台执行进程,只是一个在同一线程上,另一个在不同线程上?

2
@Jon:当我使用Dispatcher.BeginInvoke时,我的代码运行正常,并且在Dispatcher中。调用我的应用程序,让我等待几秒钟,然后初始化所有控件,然后启动,请您帮我找出我卡住的确切位置?
SharpUrBrain 2011年

6
@SharpUrBrain:Control.BeginInvoke类似于Dispatcher.BeginInvoke,但适用于WinForms(而Dispatcher适用于WPF和Silverlight)。
乔恩·斯基特

4
@SharpUrBrain:我建议您问一个特定的问题,而不要继续发表评论-当然,请先检查是否有人已经问过相同的问题。
乔恩·斯基特

2
@AZ:是的,“在UI线程上”是指在拥有特定控件句柄的特定“ UI线程”上。通常,只有一个UI线程,但是可能有多个UI线程,在高级应用程序中,有您为什么需要它们的原因。从技术上讲,任何(正常?)线程都可以启动UI消息泵并成为UI线程,并且以后可以关闭消息泵而不再是UI线程。(不过,我认为这不是尝试使用线程池线程的方法。)
Rob Parker

46

在Jon Skeet的回复的基础上,有时您想调用委托并等待其执行完成,然后再继续当前线程。在这种情况下,Invoke通话就是您想要的。

在多线程应用程序中,您可能不希望线程等待委托完成执行,尤其是如果该委托执行I / O(这可能会使委托和您的线程阻塞)。

在这种情况下,BeginInvoke将很有用。通过调用它,您是在告诉委托启动,但是随后您的线程可以与委托并行地执行其他操作。

使用BeginInvoke会增加代码的复杂性,但有时候提高性能值得这种复杂性。


27

Control.Invoke()和之间的区别Control.BeginInvoke()是,

  • BeginInvoke()将在GUI线程上安排异步操作。安排异步操作后,您的代码将继续。稍后(您不知道确切的时间),您的异步操作将被执行
  • Invoke() 将执行您的异步操作(在GUI线程上),然后等待操作完成。

合理的结论是,您传递给的委托Invoke()可以具有参数或返回值,而传递给的委托BeginInvoke()则不能(必须使用EndInvoke检索结果)。


20

只是给出一个简短的示例,以了解它们之间的差异所产生的影响

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,则在睡眠3秒后会弹出MessageBox。因此,显示了异步(BeginInvoke)和同步(Invoke)调用的效果。


9

Delegate.BeginInvoke()异步将委托的调用排队,并立即返回控件。使用Delegate.BeginInvoke()时,应在回调方法中调用Delegate.EndInvoke()以获取结果。

Delegate.Invoke()在同一线程中同步调用委托。

MSDN文章


8

只需添加为什么和何时使用Invoke()。

Invoke()和BeginInvoke()都将您指定给调度程序线程的代码封送。

但是与BeginInvoke()不同,Invoke()会暂停您的线程,直到调度程序执行您的代码为止。如果需要在用户提供某种反馈之前暂停异步操作,则可能要使用Invoke()。

例如,您可以调用Invoke()来运行显示“确定/取消”对话框的代码段。用户单击按钮并完成编组的代码后,将返回invoke()方法,您可以根据用户的响应进行操作。

请参阅C#第31章中的Pro WPF

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.