Invoke和BeginInvoke

nia*_*iao 17 c# asynchronous invoke begininvoke

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

但是,以下代码中的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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

Jus*_*ier 19

首先,从您的链接:

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

从MSDN:

BeginInvoke在创建控件的基础句柄的线程上异步执行指定的委托.

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

或者,Invoke同步的.文本框将被更新,因为调用线程将在继续执行之前等待调用完成.

  • 一个小问题 - 当方法返回时它没有被执行,它是作为火完成而忘记 - 它被激发到COM/winapi以太 (2认同)

Ton*_*ion 8

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

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

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

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

希望这可以帮助!

  • 调用BeginInvoke并不意味着它没有在UI线程上执行.这意味着它在与"this"相关联的线程上异步调用,这可能是UI线程. (13认同)
  • "*你不应该更新BeginXXX方法中的GUI组件,因为它们在另一个线程中运行到GUI线程,与你的Invoke方法相反.*"这是错误的,应该纠正,因为它可能会误导他人(另外,这个是接受的答案......). (11认同)
  • 从MSDN:"在创建控件的底层句柄的线程上异步执行指定的委托".因此,如果从UI线程调用它,它将被放置在队列中并在UI线程空闲时执行.在当前正在执行的方法返回之后. (8认同)

Chr*_*s S 5

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

在创建控件的基础句柄的线程上异步执行指定的委托.

但是,Control.BeginInvoke只需使用PostMessage并返回 - 不会Thread创建CLR .

PostMessage函数将消息放入(发布)与创建指定窗口的线程关联的消息队列中,并返回而不等待线程处理消息.

本文总结了是否使用InvokeBeginInvoke相当好:

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

  • 如果您通过BeginInvoke调用的函数访问共享状态(UI线程和其他线程之间共享的状态),则表示您遇到了麻烦.状态可能会在您调用BeginInvoke和实际执行包装函数之间发生变化,从而导致很难找到计时问题.
  • 如果要将引用参数传递给通过BeginInvoke调用的函数,则必须确保在函数完成之前没有其他人修改传递的对象.通常,人们在将对象传递给BeginInvoke之前克隆该对象,这完全避免了这个问题.