async和await详解

  • async和await详解已关闭评论
  • 116 次浏览
  • A+
所属分类:.NET技术
摘要

 async和await详解  1.非UI线程中执行        上面是控制台应用程序,主线程的ID为1,第一个await和后面的代码都是子线程完成的。第二个await和后面的代码,也是子线程完成的。在非UI线程中执行的async异步方法,await等待的异步操作和后面要执行的代码,都是从线程池获取一个线程来执行的。

 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 }

 

 

 

 async和await详解

 

 

 上面是控制台应用程序,主线程的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 }

async和await详解

 

 

 在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 = 0; 20             Task task1 = Task.Factory.StartNew(() => 21             { 22                 Value++; 23                 Thread.Sleep(100); 24             }); 25             await task1; 26             return Value; 27         } 28     } 29 }

async和await详解

 

 

 执行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 = 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;这行代码。谁也不让谁的等待下去,这就是死锁了。