一.委托的同步和異步:
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線程 |