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