參考微軟網頁:web
使用 Async 和 Await 的異步編程 (C#) https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/async/index 演練:使用 Async 和 Await 訪問 Web (C#) https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/concepts/async/walkthrough-accessing-the-web-by-using-async-and-await await(C# 參考) https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/keywords/await
今天作async await實驗時發現一個奇怪的語法現象:編程
static void test() { Console.WriteLine("asyncawaittest"); } private void btnasyncawait_Click(object sender, EventArgs e) { new Thread(test) { IsBackground = true }.Start(); //**注意** IsBackground = true後面沒有分號「;」 //new Thread(test) { IsBackground = true, Name = "mythreadname" }.Start(); //也成功 }
以上代碼成功,改爲以下代碼也成功:c#
static void test() { Console.WriteLine("asyncawaittest thread id = "+Thread.CurrentThread.ManagedThreadId+" thread name="+Thread.CurrentThread.Name); } private void btnasyncawait_Click(object sender, EventArgs e) { Console.WriteLine("main thread id = " + Thread.CurrentThread.ManagedThreadId); new Thread(test) { IsBackground = true, Name = "mythreadname" }.Start();//**注意** }
但在true後面加上一個分號以後出現語法錯誤。後來經過學習才明白這種用法在叫作「對象初始化器」,好比:異步
Person person = new Person(); person.Name = "Slark"; person.Age = 100; person.Address = "Xi'an"; 這裏咱們用了一行建立對象語句,加三行賦值語句。這裏光person這個變量就出現了4遍,繁瑣。用對象初始化器來代替這些操做: Person person = new Person { Name = "Slark", Age = 100, Address = "Xi'an" };
c#中除了對象初始化器以外,還有集合初始化器:async
List<int> intList = new List<int>(); intList.Add(1); intList.Add(2); intList.Add(3); 好,這裏咱們用4行代碼建立了一個3個元素的集合。集合初始化器的出現大大減小了咱們對這種操做的代碼量。其對應的集合初始化器代碼爲: List<int> intList = new List<int> { 1, 2, 3 };
下面來真正進入async和await學習中來,先看一段代碼:ide
private void btnasyncawait_Click(object sender, EventArgs e) { Console.WriteLine("main thread id = " + Thread.CurrentThread.ManagedThreadId); Say(); } private async static void Say() { Console.WriteLine("Say thread id = " + Thread.CurrentThread.ManagedThreadId); var t = TestAsync(); Thread.Sleep(1100); //主線程在執行一些任務 Console.WriteLine("Main Thread"); //主線程完成標記 Console.WriteLine(await t); //await 主線程等待取異步返回結果 } static async Task<string> TestAsync() { return await Task.Run(() => { Console.WriteLine("await task thread id = " + Thread.CurrentThread.ManagedThreadId); Thread.Sleep(1000); //異步執行一些任務 return "Hello World"; //異步執行完成標記 }); }
以上代碼能夠成功運行,點擊按鈕再次,結果以下:異步編程
main thread id = 8 Say thread id = 8 await task thread id = 9 Main Thread Hello World main thread id = 8 Say thread id = 8 await task thread id = 9 Main Thread Hello World
去掉TestAsync()中的async和await即代碼以下時:函數
static Task<string> TestAsync() { return Task.Run(() => { Console.WriteLine("await task thread id = " + Thread.CurrentThread.ManagedThreadId); Thread.Sleep(1000); //異步執行一些任務 return "Hello World"; //異步執行完成標記 }); }
代碼也能成功運行,點擊按鈕再次,結果以下:學習
main thread id = 8 Say thread id = 8 await task thread id = 9 Main Thread Hello World main thread id = 8 Say thread id = 8 await task thread id = 10 Main Thread Hello World
當我將代碼修改以下時,發現一個很不明白的現象(主要是將Say()函數中的t以前的await去掉了):測試
private void btnasyncawait_Click(object sender, EventArgs e) { Console.WriteLine("main thread id = " + Thread.CurrentThread.ManagedThreadId); Say(); } private async static void Say() { Console.WriteLine("Say thread id = " + Thread.CurrentThread.ManagedThreadId); var t = TestAsync(); Thread.Sleep(1100); //主線程在執行一些任務 Console.WriteLine("Main Thread"); //主線程完成標記 Console.WriteLine( t); //注意此處t以前沒有await } static async Task<string> TestAsync() { return await Task.Run(() => { Console.WriteLine("await task thread id = " + Thread.CurrentThread.ManagedThreadId); Thread.Sleep(1000); //異步執行一些任務 return "Hello World"; //異步執行完成標記 }); }
打印出來的結果爲:
main thread id = 10 Say thread id = 10 await task thread id = 11 Main Thread System.Threading.Tasks.Task`1[System.String]
再將代碼修改以下:
private void btnasyncawait_Click(object sender, EventArgs e) { Console.WriteLine("main thread id = " + Thread.CurrentThread.ManagedThreadId); Say(); } private async static void Say() { Console.WriteLine("Say thread id = " + Thread.CurrentThread.ManagedThreadId); var t = TestAsync(); Thread.Sleep(1100); //主線程在執行一些任務 Console.WriteLine("Main Thread"); //主線程完成標記 Console.WriteLine( t); } static Task<string> TestAsync() { return Task.Run(() => { Console.WriteLine("await task thread id = " + Thread.CurrentThread.ManagedThreadId); Thread.Sleep(1000); //異步執行一些任務 return "Hello World"; //異步執行完成標記 }); }
打印結果以下:
main thread id = 9 Say thread id = 9 await task thread id = 10 Main Thread System.Threading.Tasks.Task`1[System.String]
還有一段測試代碼以下:
private void trfun() { var ttr = Task.Run<String>(() => { Thread.Sleep(3000); return "abc"; }); string rs = ttr.Result;//阻塞3秒 Console.WriteLine("ttr.result=" + rs); }
主程序中調用trfun()函數,則主程序要等待大約3秒鐘以後纔打印出結果abc以後才往下執行。換成以下代碼:
private void btnasyncawait_Click(object sender, EventArgs e) { Console.WriteLine("main thread id = " + Thread.CurrentThread.ManagedThreadId); trfun(); Say(); } private async void trfun() { var ttr = Task.Run<String>(() => { Thread.Sleep(3000); return "abc"; }); string rs = await ttr;//當程序執行到此句時不會再向下反而是快速進入btnasyncawait_Click中的Say() Console.WriteLine("trfun thread id = " + Thread.CurrentThread.ManagedThreadId);//此句須要等3秒才能執行,且處於主線程ID中 Console.WriteLine("ttr.result=" + rs); }
打印出來的結果以下:
main thread id = 9 Say thread id = 9 await task thread id = 11 Main Thread Hello World trfun thread id = 9 ttr.result=abc
這種異步處理對於btnasyncawait_Click及其主線程來講不會阻塞,阻塞的只是trfun中的await ttr語句。
還有一篇帖子 C#Winform裏的async和await異步 http://www.javashuo.com/article/p-bltudvjy-cc.html 講得也不錯
1個按鈕,2個textbox,下面這樣能夠正確異步,窗體也不會死掉,textBox2會先有結果,textBox1再有結果 private async void button1_Click(object sender, EventArgs e) { Does(); textBox2.Text = "1"; } private Task<string> DoWork() { return Task.Run(() => { Thread.Sleep(4000); return "Done with work!"; } ); } private async void Does() { string text = await DoWork(); textBox1.Text = text; } 若是把按鈕事件改爲下面這樣,窗體不會死,但不會異步執行 private async void button1_Click(object sender, EventArgs e) { textBox2.Text =await DoWork(); textBox2.Text = "1"; }