C#委托同步异步说明,并比较control调用Invoke和BeginInvoke的异同
一.委托的同步和异步:
1.同步
使用Invoke调用同步,或直接写fun1("func"),在fun1.Invoke这一步会明显的阻塞线程
使用:
static void Main(string[] args) { Thread.CurrentThread.Name = "Main"; //定义一个带返回值的委托 var fun1 = new Func<string, int>(x => { Thread.Sleep(1000); Console.WriteLine(x); Console.WriteLine($"ThreadId:{Thread.CurrentThread.ManagedThreadId} ThreadName:{Thread.CurrentThread.Name}"); return 1; }); fun1.Invoke("fun1"); Console.WriteLine("Main"); Console.WriteLine($"ThreadId:{Thread.CurrentThread.ManagedThreadId} ThreadName:{Thread.CurrentThread.Name}"); Console.ReadKey(); }
运行结果:
结果说明:
同步委托运行在主线程上
2.异步
使用BeginInvoke来调用异步,EndInvoke来获取返回值,AsyncCallback定义异步完成回调函数
使用:
static void Main(string[] args) { Thread.CurrentThread.Name = "Main"; //定义一个带返回值的委托 var fun1 = new Func<string, int>(x => { Thread.CurrentThread.Name = "fun1"; Console.WriteLine(x); Console.WriteLine($"ThreadId:{Thread.CurrentThread.ManagedThreadId} ThreadName:{Thread.CurrentThread.Name}"); return 1; }); fun1.BeginInvoke("fun1", t => { //var fun2 = t.AsyncState as Func<string, int>;//如果不是lambda表达式需要用该方式获得委托 //获取返回值 int ret = fun1.EndInvoke(t); Console.WriteLine($"callback return:{ret}"); Console.WriteLine($"ThreadId:{Thread.CurrentThread.ManagedThreadId} ThreadName:{Thread.CurrentThread.Name}"); }, null); Thread.Sleep(1000); Console.WriteLine("Main"); Console.WriteLine($"ThreadId:{Thread.CurrentThread.ManagedThreadId} ThreadName:{Thread.CurrentThread.Name}"); Console.ReadKey(); }
运行结果:
结果说明:
异步委托并不是运行在主线程上,而是运行在独立的线程上,是异步执行的
二.control的Invoke和BeginInvoke
1.Invoke
使用:
private void button1_Click(object sender, EventArgs e) { Thread.CurrentThread.Name = "UIThread"; this.Invoke(new Action(() => { Thread.Sleep(5000); Debug.WriteLine($"Invoke ThreadId:{Thread.CurrentThread.ManagedThreadId} ThreadName:{Thread.CurrentThread.Name}"); })); Debug.WriteLine($"Main ThreadId:{Thread.CurrentThread.ManagedThreadId} ThreadName:{Thread.CurrentThread.Name}"); }
运行结果:
结果说明:
可以明显的感到Invoke阻塞了界面5s后,才执行后面的代码
Invoke内的委托在UI线程上执行,是同步的
2.BeginInvoke
使用:
private void button1_Click(object sender, EventArgs e) { Thread.CurrentThread.Name = "UIThread"; this.BeginInvoke(new Action(() => { Debug.WriteLine($"BeginInvoke ThreadId:{Thread.CurrentThread.ManagedThreadId} ThreadName:{Thread.CurrentThread.Name}"); })); Debug.WriteLine($"Main ThreadId:{Thread.CurrentThread.ManagedThreadId} ThreadName:{Thread.CurrentThread.Name}"); Thread.Sleep(5000); }
运行结果:
结果说明:
可以明显看到界面卡了5s后,才先执行的BeginInvoke内的委托
结论:BeginInvoke内的委托在UI线程上执行,并不是异步,只是放在UI线程中最后执行。
三.结论
delegate.Invoke | 运行在主线程上,同步执行,并立即执行,会阻塞主线程 |
delegate.BeginInvoke | 运行在独立线程上,异步执行, 并立即执行,不会阻塞主线程 |
Control.Invoke | 运行在UI线程上,同步执行,并立即执行,会阻塞UI线程 |
Control.BeginInvoke | 运行在UI线程上,不是异步执行,等UI线程其他操作完成才执行,会阻塞UI线程 |