Invoke和BeginInvoke

时间:2009-12-15 19:38:19

标签: c# asynchronous invoke begininvoke

问候, 我正在用C#开发一些应用程序。目前我正在处理线程,我有一个问题,我在脑海里。 Invoke和BeginInvoke有什么区别? 我读了一些帖子,我在这里找到了一些有用的信息:here

但是,以下代码中的Invoke和BeginInvoke有什么区别:

private void ProcessRoutine()
{
   for (int nValue = StartFrom; nValue <= EndTo; nValue++)
   {
      this.Invoke(this.MyDelegate, nValue);
      //this.BeginInvoke(this.MyDelegate, nValue);
   }
   MessageBox.Show("Counting complete!");
}
private void MessageHandler(int progress)
{
    lblStatus.Text = lblStatus.Text = "Processing item: " + progress.ToString();
    progressBar1.Value = progress;
}

其中MyDelegate是对MessageHandler函数的引用。

我注意到使用BeginInvoke lblStatus.Text没有刷新,使用Invoke刷新标签。 另外我知道Invoke等待它的执行完成。 我感兴趣的最重要的案例是为什么在这种情况下刷新标签文本有所不同。

5 个答案:

答案 0 :(得分:19)

首先,从您的链接开始:

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

来自MSDN:

  

BeginInvoke在创建控件的底层句柄的线程上异步执行指定的委托。

总结一下,BeginInvoke 异步。当从UI线程调用BeginInvoke时,请求将与UI线程并行执行。这意味着它可能直到当前正在执行的方法返回后才执行。因此,在这种情况下,文本框将永远不会更新,因为for循环不会被中断,因为调用线程不会等待此事件在继续之前完成。

或者,Invoke同步。文本框将被更新,因为调用线程将等待调用完成后再继续执行。

答案 1 :(得分:7)

使用Invoke,方法将被执行,应用程序将等待它完成。

使用BeginInvoke,方法被Asychnronously调用,应用程序继续执行,同时执行BeginInvoke中引用的方法。

使用BeginInvoke,您需要调用EndInvoke来获取使用BeginIvnoke执行的方法的结果。

您不应该更新BeginXXX方法中的GUI组件,因为它们在另一个线程中运行到GUI线程,这与您的Invoke方法相反。您无法在与GUI线程不同的线程中访问GUI组件。

希望这有帮助!

答案 2 :(得分:5)

Control.BeginInvoke不能在不同的线程(或线程池)上工作,委托.BeginInvoke也可以。 MSDN的一个班轮说:

  

执行指定的委托   在线程上异步的那个   控制的底层手柄是   创建于。

Control.BeginInvoke仅使用PostMessage并返回 - 未创建CLR Thread

  

PostMessage功能放置   (发布)消息队列中的消息   与线程相关联   创建了指定的窗口和   返回而不等待线程   处理消息。

This article总结了是否能很好地使用InvokeBeginInvoke

  

你问哪个功能。它   真的取决于你的要求。如果   您希望完成UI更新   在继续之前,您使用Invoke。如果   我没有这样的要求   建议使用BeginInvoke,因为它   看似它的线程   “快点”。有一些问题   但是使用BeginInvoke。

     
      
  • 如果您通过BeginInvoke调用的函数访问共享状态   (UI线程之间共享的状态   和其他线程),你在   麻烦。国家可能会改变   在你打电话之间   BeginInvoke和包装时   函数实际执行,导致   很难找到计时问题。
  •   
  • 如果要将参考参数传递给名为via的函数   BeginInvoke,那么你必须确保   没有人修改传递的   函数完成前的对象。   通常,人们克隆对象   在将它传递给BeginInvoke之前,   这完全避免了这个问题。
  •   

答案 3 :(得分:1)

BeginInvoke在另一个线程上执行方法体,并允许当前线程继续。如果您尝试直接从另一个线程更新控件属性,则会抛出异常。

答案 4 :(得分:0)

这基本上归结为您是否希望同步或异步更新控件。这一切都取决于您的具体情况。