C#异步编程のWPF Invoke和BeginInvoke

我们先看个简单的例子:

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Console.WriteLine("BeforeInvoke1");
            Dispatcher.Invoke((Action)(() => {
                Thread.Sleep(1000);
                Console.WriteLine("Invoke1");
            }));
            Console.WriteLine("EndInvoke1");

            Console.WriteLine("BeforeInvoke2");
            Dispatcher.BeginInvoke((Action)(() => {
                Thread.Sleep(1000);
                Console.WriteLine("BeginInvoke2");
            }));
            Console.WriteLine("EndInvoke2");
        }  

 执行的结果为:

以上结果说明,Invoke为同步,必须等待其中的委托完成后才能向后执行

         BeginInvoke为异步,不必等待它所委托的方法完成后再执行(比较类似的有其他Begin方法)

首先说下,invoke和begininvoke的使用有两种情况:

  1. control中的invoke、begininvoke。

  2. delegrate中的invoke、begininvoke。  

  这两种情况是不同的,我们这里要讲的是第1种。下面我们在来说下.NET中对invoke和begininvoke的官方定义。

  control.invoke(参数delegate)方法:在拥有此控件的基础窗口句柄的线程上执行指定的委托。

  control.begininvoke(参数delegate)方法:在创建控件的基础句柄所在线程上异步执行指定委托。

  根据这两个概念我们大致理解invoke表是同步、begininvoke表示异步。但是如何来进行同步和异步呢?我们来做一个测试。

invoke 例子:

 private void button1_Click(object sender, EventArgs e) 
{            
 MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"AAA");            
 invokeThread = new Thread(new ThreadStart(StartMethod));              invokeThread.Start();           
 string a = string.Empty;             
for (int i = 0; i < 3; i++)      //调整循环次数,看的会更清楚             
{                
 Thread.Sleep(1000);                    a = a + "B";             
}            
 MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+a); 
}

 private void StartMethod()
 {           
  MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"CCC");             button1.Invoke(new invokeDelegate(invokeMethod));               MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"DDD"); 
}

 private void invokeMethod() 
{             //Thread.Sleep(3000);            
 MessageBox.Show    (Thread.CurrentThread.GetHashCode().ToString()+ "EEE");
 } 

结论:我们运行后,看下程序的运行顺序,1AAA->3CCC和1BBB->1EEE ->3DDD 。
     

结论:我们运行后,看下程序的运行顺序,1AAA->3CCC和1BBB->1EEE ->3DDD 。 

解释:主线程运行1AAA,然后1BBB和子线程3CCC同时执行,然后通过invoke来将invokemethod方法提交给主线程,然后子线程等待主线程执行,直到主线程将invokemethod方法执行完成(期间必须等待主线程的任务执行完成,才会去执行invoke提交的任务),最后执行子线程3DDD。

begininvoke 例子:

private void button1_Click(object sender, EventArgs e) 
{             
MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"AAA");            
 invokeThread = new Thread(new ThreadStart(StartMethod));             invokeThread.Start();            
 string a = string.Empty;             
for (int i = 0; i < 3; i++)      //调整循环次数,看的会更清楚            
 {       
          Thread.Sleep(1000);                    a = a + "B";            
 }             
MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+a); 
}

 private void StartMethod()
 {            
 MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"CCC");            
 button1.BeginInvoke(new invokeDelegate(invokeMethod));               MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"DDD"); 
}

 private void beginInvokeMethod()         
{            
 //Thread.Sleep(3000);             
MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "EEEEEEEEEEEE");        
 }

结论: 我们运行后看看执行的结果:1AAA->1BBB和3CCC->1EEE和3DDD。

解释: 主线程运行1AAA,然后1BBB和子线程3CCC同时执行,然后通过begininvoke来将invokemethod方法提交给主线程,然后主线程执行1EEE(主线程自己的任务执行完成), 同时子线程继续执行3DDD。

通过这个两段代码的测试比较,我们会发现其实invoke和begininvoke所提交的委托方法都是在主线程中执行的,其实根据我invoke和begininvoke的定义我们要在子线程中来看这个问题,在invoke例子中我们会发现invoke所提交的委托方法执行完成后,才能继续执行DDD;在begininvoke例子中我们会发现begininvoke所提交的委托方法后,子线程讲继续执行DDD,不需要等待委托方法的完成。 那么现在我们在回想下invoke(同步)和begininvoke(异步)的概念,其实它们所说的意思是相对于子线程而言的,其实对于控件的调用总是由主线程来执行的。我们很多人搞不清这个同步和异步,主要还是因为我们把参照物选错了。其实有时候光看概念是很容易理解错误的。

原文地址:https://www.cnblogs.com/xietianjiao/p/5249740.html