西河刘卡车医 发表于 2022-6-23 14:29:31

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 } 
 
 
 https://img2022.cnblogs.com/blog/2004791/202206/2004791-20220620150659171-254527893.png
 
 
 上面是控制台应用程序,主线程的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 }https://img2022.cnblogs.com/blog/2004791/202206/2004791-20220620151356803-751821985.png
 
 
 在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 }https://img2022.cnblogs.com/blog/2004791/202206/2004791-20220620152450139-1456128615.png
 
 
 执行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         privatevoid 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;这行代码。谁也不让谁的等待下去,这就是死锁了。 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: async和await详解