async和await詳解
1.非UI執行緒中執行
Test()函式帶有async 和await ,回傳值寫成Task,
1 using System; 2 using System.Threading; 3 using System.Threading.Tasks; 4 5 namespace _00_測驗 6 { 7 class Program 8 { 9 static void Main(string[] args) 10 { 11 Console.WriteLine($"Main Start:{Thread.CurrentThread.ManagedThreadId}"); 12 Task task = Test(); 13 Console.WriteLine($"Main End:{Thread.CurrentThread.ManagedThreadId}"); 14 Console.ReadKey(); 15 } 16 private async static Task Test() 17 { 18 Console.WriteLine($"當前主執行緒ID::{Thread.CurrentThread.ManagedThreadId}"); 19 Console.WriteLine($"是否是執行緒池執行緒:{Thread.CurrentThread.IsThreadPoolThread}"); 20 Task task1 = Task.Factory.StartNew(() => 21 { 22 Thread.Sleep(100); 23 Console.WriteLine($"task1:{Thread.CurrentThread.ManagedThreadId}"); 24 Console.WriteLine($"是否是執行緒池執行緒:{Thread.CurrentThread.IsThreadPoolThread}"); 25 }); 26 await task1; 27 28 Console.WriteLine($"task1 結束后的執行緒ID:{Thread.CurrentThread.ManagedThreadId}"); 29 Console.WriteLine($"是否是執行緒池執行緒:{Thread.CurrentThread.IsThreadPoolThread}"); 30 31 await Task.Run(() => 32 { 33 Thread.Sleep(100); 34 Console.WriteLine($"task2:{Thread.CurrentThread.ManagedThreadId}"); 35 Console.WriteLine($"是否是執行緒池執行緒:{Thread.CurrentThread.IsThreadPoolThread}"); 36 }); 37 Console.WriteLine($"Test End:{Thread.CurrentThread.ManagedThreadId}"); 38 Console.WriteLine($"是否是執行緒池執行緒:{Thread.CurrentThread.IsThreadPoolThread}"); 39 } 40 } 41 }

上面是控制臺應用程式,主執行緒的ID為1,第一個await和后面的代碼都是子執行緒完成的,第二個await和后面的代碼,也是子執行緒完成的,在非UI執行緒中執行的async異步方法,await等待的異步操作和后面要執行的代碼,都是從執行緒池獲取一個執行緒來執行的,
2.UI執行緒中執行
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Threading; 9 using System.Threading.Tasks; 10 using System.Windows.Forms; 11 12 namespace _009__資料庫 13 { 14 public partial class Form1 : Form 15 { 16 public Form1() 17 { 18 InitializeComponent(); 19 } 20 21 private async void button1_Click(object sender, EventArgs e) 22 { 23 Console.WriteLine($"Main Start:{Thread.CurrentThread.ManagedThreadId}"); 24 Task task = Test(); 25 await task; 26 Console.WriteLine($"Main End:{Thread.CurrentThread.ManagedThreadId}"); 27 Console.ReadKey(); 28 } 29 private async static Task Test() 30 { 31 Console.WriteLine($"當前主執行緒ID::{Thread.CurrentThread.ManagedThreadId}"); 32 Console.WriteLine($"是否是執行緒池執行緒:{Thread.CurrentThread.IsThreadPoolThread}"); 33 Task task1 = Task.Factory.StartNew(() => 34 { 35 Thread.Sleep(100); 36 Console.WriteLine($"task1:{Thread.CurrentThread.ManagedThreadId}"); 37 Console.WriteLine($"是否是執行緒池執行緒:{Thread.CurrentThread.IsThreadPoolThread}"); 38 }); 39 await task1; 40 41 Console.WriteLine($"task1 結束后的執行緒ID:{Thread.CurrentThread.ManagedThreadId}"); 42 Console.WriteLine($"是否是執行緒池執行緒:{Thread.CurrentThread.IsThreadPoolThread}"); 43 44 await Task.Run(() => 45 { 46 Thread.Sleep(100); 47 Console.WriteLine($"task2:{Thread.CurrentThread.ManagedThreadId}"); 48 Console.WriteLine($"是否是執行緒池執行緒:{Thread.CurrentThread.IsThreadPoolThread}"); 49 }); 50 Console.WriteLine($"Test End:{Thread.CurrentThread.ManagedThreadId}"); 51 Console.WriteLine($"是否是執行緒池執行緒:{Thread.CurrentThread.IsThreadPoolThread}"); 52 } 53 } 54 }

在UI執行緒中,async切換執行緒的規律和非UI執行緒不一樣了,在UI執行緒中,await后面緊跟的代碼,一直都是在UI執行緒中執行的,
注意:非UI執行緒中,await后面的動作都是子執行緒完成的;UI執行緒中,await后面的動作都是主執行緒完成的,
3.帶回傳值的異步方法
非UI執行緒
1 using System; 2 using System.Threading; 3 using System.Threading.Tasks; 4 5 namespace _00_測驗 6 { 7 class Program 8 { 9 static void Main(string[] args) 10 { 11 Console.WriteLine($"Main Start:{Thread.CurrentThread.ManagedThreadId}"); 12 Task<int> task = Test(); 13 Console.WriteLine($"結果為:{task.Result}"); 14 Console.WriteLine($"Main End:{Thread.CurrentThread.ManagedThreadId}"); 15 Console.ReadKey(); 16 } 17 private async static Task<int> Test() 18 { 19 int Value = https://www.cnblogs.com/dfcq/p/0; 20 Task task1 = Task.Factory.StartNew(() => 21 { 22 Value++; 23 Thread.Sleep(100); 24 }); 25 await task1; 26 return Value; 27 } 28 } 29 }

執行Test()異步方法,然后獲取異步方法的回傳值,執行異步方法的執行緒會一直阻塞,直到等到要獲取的回傳值,但是,在UI執行緒中,執行異步方案的是主執行緒,直接就死鎖了,
UI執行緒
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Threading; 9 using System.Threading.Tasks; 10 using System.Windows.Forms; 11 12 namespace _009__資料庫 13 { 14 public partial class Form1 : Form 15 { 16 public Form1() 17 { 18 InitializeComponent(); 19 } 20 21 private void button1_Click(object sender, EventArgs e) 22 { 23 Console.WriteLine($"Main Start:{Thread.CurrentThread.ManagedThreadId}"); 24 Task<int> task = Test(); 25 Console.WriteLine($"結果為:{task.Result}"); 26 Console.WriteLine($"Main End:{Thread.CurrentThread.ManagedThreadId}"); 27 Console.ReadKey(); 28 } 29 private async static Task<int> Test() 30 { 31 int Value = https://www.cnblogs.com/dfcq/p/0; 32 Task task1 = Task.Factory.StartNew(() => 33 { 34 Value++; 35 Thread.Sleep(100); 36 }); 37 await task1; 38 return Value; 39 } 40 } 41 }
在winform中,點擊按鈕,界面直接卡死了!!!
分析, 執行Test()異步方法,然后獲取異步方法的回傳值,但是在UI執行緒中,await后面的操作是UI執行緒執行的,那么,首先異步方法執行了await中的異步任務,UI執行緒已經開始等這個執行結果了,UI執行緒阻塞等待中;而await后面的
return Value;這一行,需要UI執行緒執行啊,此時UI執行緒阻塞等結果呢無法執行其他操作,就這么UI等回傳值,子執行緒等UI執行緒等UI執行緒來執行 return Value;這行代碼,誰也不讓誰的等待下去,這就是死鎖了,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/493618.html
標籤:C#
