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 = 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 = 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;这行代码。谁也不让谁的等待下去,这就是死锁了。
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |