async和await详解

打印 上一主题 下一主题

主题 646|帖子 646|积分 1938

 async和await详解
 1.非UI线程中执行
  1. Test()函数带有async 和await ,返回值写成Task。
复制代码
  1. 1 using System;
  2. 2 using System.Threading;
  3. 3 using System.Threading.Tasks;
  4. 4
  5. 5 namespace _00_测试
  6. 6 {
  7. 7     class Program
  8. 8     {
  9. 9         static void Main(string[] args)
  10. 10         {
  11. 11             Console.WriteLine($"Main Start:{Thread.CurrentThread.ManagedThreadId}");
  12. 12             Task task = Test();
  13. 13             Console.WriteLine($"Main End:{Thread.CurrentThread.ManagedThreadId}");
  14. 14             Console.ReadKey();
  15. 15         }
  16. 16         private async static Task Test()
  17. 17         {
  18. 18             Console.WriteLine($"当前主线程ID::{Thread.CurrentThread.ManagedThreadId}");
  19. 19             Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
  20. 20             Task task1 = Task.Factory.StartNew(() =>
  21. 21             {
  22. 22                 Thread.Sleep(100);
  23. 23                 Console.WriteLine($"task1:{Thread.CurrentThread.ManagedThreadId}");
  24. 24                 Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
  25. 25             });
  26. 26             await task1;
  27. 27
  28. 28             Console.WriteLine($"task1 结束后的线程ID:{Thread.CurrentThread.ManagedThreadId}");
  29. 29             Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
  30. 30
  31. 31             await Task.Run(() =>
  32. 32             {
  33. 33                 Thread.Sleep(100);
  34. 34                 Console.WriteLine($"task2:{Thread.CurrentThread.ManagedThreadId}");
  35. 35                 Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
  36. 36             });
  37. 37             Console.WriteLine($"Test End:{Thread.CurrentThread.ManagedThreadId}");
  38. 38             Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
  39. 39         }
  40. 40     }
  41. 41 }
复制代码
 
 
 
 
 
 
 上面是控制台应用程序,主线程的ID为1,第一个await和后面的代码都是子线程完成的。第二个await和后面的代码,也是子线程完成的。在非UI线程中执行的async异步方法,await等待的异步操作和后面要执行的代码,都是从线程池获取一个线程来执行的。
 
2.UI线程中执行
  1. 1 using System;
  2. 2 using System.Collections.Generic;
  3. 3 using System.ComponentModel;
  4. 4 using System.Data;
  5. 5 using System.Drawing;
  6. 6 using System.Linq;
  7. 7 using System.Text;
  8. 8 using System.Threading;
  9. 9 using System.Threading.Tasks;
  10. 10 using System.Windows.Forms;
  11. 11
  12. 12 namespace _009__数据库
  13. 13 {
  14. 14     public partial class Form1 : Form
  15. 15     {
  16. 16         public Form1()
  17. 17         {
  18. 18             InitializeComponent();
  19. 19         }
  20. 20
  21. 21         private async void button1_Click(object sender, EventArgs e)
  22. 22         {
  23. 23             Console.WriteLine($"Main Start:{Thread.CurrentThread.ManagedThreadId}");
  24. 24             Task task = Test();
  25. 25             await task;
  26. 26             Console.WriteLine($"Main End:{Thread.CurrentThread.ManagedThreadId}");
  27. 27             Console.ReadKey();
  28. 28         }
  29. 29         private async static Task Test()
  30. 30         {
  31. 31             Console.WriteLine($"当前主线程ID::{Thread.CurrentThread.ManagedThreadId}");
  32. 32             Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
  33. 33             Task task1 = Task.Factory.StartNew(() =>
  34. 34             {
  35. 35                 Thread.Sleep(100);
  36. 36                 Console.WriteLine($"task1:{Thread.CurrentThread.ManagedThreadId}");
  37. 37                 Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
  38. 38             });
  39. 39             await task1;
  40. 40
  41. 41             Console.WriteLine($"task1 结束后的线程ID:{Thread.CurrentThread.ManagedThreadId}");
  42. 42             Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
  43. 43
  44. 44             await Task.Run(() =>
  45. 45             {
  46. 46                 Thread.Sleep(100);
  47. 47                 Console.WriteLine($"task2:{Thread.CurrentThread.ManagedThreadId}");
  48. 48                 Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
  49. 49             });
  50. 50             Console.WriteLine($"Test End:{Thread.CurrentThread.ManagedThreadId}");
  51. 51             Console.WriteLine($"是否是线程池线程:{Thread.CurrentThread.IsThreadPoolThread}");
  52. 52         }
  53. 53     }
  54. 54 }
复制代码

 
 
 在UI线程中,async切换线程的规律和非UI线程不一样了。在UI线程中,await后面紧跟的代码,一直都是在UI线程中执行的。
注意:非UI线程中,await后面的动作都是子线程完成的;UI线程中,await后面的动作都是主线程完成的。
3.带返回值的异步方法
非UI线程
  1. 1 using System;
  2. 2 using System.Threading;
  3. 3 using System.Threading.Tasks;
  4. 4
  5. 5 namespace _00_测试
  6. 6 {
  7. 7     class Program
  8. 8     {
  9. 9         static void Main(string[] args)
  10. 10         {
  11. 11             Console.WriteLine($"Main Start:{Thread.CurrentThread.ManagedThreadId}");
  12. 12             Task<int> task = Test();
  13. 13             Console.WriteLine($"结果为:{task.Result}");
  14. 14             Console.WriteLine($"Main End:{Thread.CurrentThread.ManagedThreadId}");
  15. 15             Console.ReadKey();
  16. 16         }
  17. 17         private async static Task<int> Test()
  18. 18         {
  19. 19             int Value = 0;
  20. 20             Task task1 = Task.Factory.StartNew(() =>
  21. 21             {
  22. 22                 Value++;
  23. 23                 Thread.Sleep(100);
  24. 24             });
  25. 25             await task1;
  26. 26             return Value;
  27. 27         }
  28. 28     }
  29. 29 }
复制代码

 
 
 执行Test()异步方法,然后获取异步方法的返回值,执行异步方法的线程会一直阻塞,直到等到要获取的返回值。但是,在UI线程中,执行异步方案的是主线程,直接就死锁了。
UI线程
  1. 1 using System;
  2. 2 using System.Collections.Generic;
  3. 3 using System.ComponentModel;
  4. 4 using System.Data;
  5. 5 using System.Drawing;
  6. 6 using System.Linq;
  7. 7 using System.Text;
  8. 8 using System.Threading;
  9. 9 using System.Threading.Tasks;
  10. 10 using System.Windows.Forms;
  11. 11
  12. 12 namespace _009__数据库
  13. 13 {
  14. 14     public partial class Form1 : Form
  15. 15     {
  16. 16         public Form1()
  17. 17         {
  18. 18             InitializeComponent();
  19. 19         }
  20. 20
  21. 21         private  void button1_Click(object sender, EventArgs e)
  22. 22         {
  23. 23             Console.WriteLine($"Main Start:{Thread.CurrentThread.ManagedThreadId}");
  24. 24             Task<int> task = Test();
  25. 25             Console.WriteLine($"结果为:{task.Result}");
  26. 26             Console.WriteLine($"Main End:{Thread.CurrentThread.ManagedThreadId}");
  27. 27             Console.ReadKey();
  28. 28         }
  29. 29         private async static Task<int> Test()
  30. 30         {
  31. 31             int Value = 0;
  32. 32             Task task1 = Task.Factory.StartNew(() =>
  33. 33             {
  34. 34                 Value++;
  35. 35                 Thread.Sleep(100);
  36. 36             });
  37. 37             await task1;
  38. 38             return Value;
  39. 39         }
  40. 40     }
  41. 41 }
复制代码
在winform中,点击按钮,界面直接卡死了!!!
分析, 执行Test()异步方法,然后获取异步方法的返回值,但是在UI线程中,await后面的操作是UI线程执行的。那么,首先异步方法执行了await中的异步任务,UI线程已经开始等这个执行结果了,UI线程阻塞等待中;而await后面的
  1. return Value;这一行,需要UI线程执行啊,此时UI线程阻塞等结果呢无法执行其他操作,就这么UI等返回值,子线程等UI线程等UI线程来执行  return Value;这行代码。谁也不让谁的等待下去,这就是死锁了。
复制代码
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

西河刘卡车医

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表