经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C# » 查看文章
对于async和await的使用方式、作用效果不怎么理解 ?没关系,初步看这篇就够了 - 熊泽-学习中的苦与乐
来源:cnblogs  作者:熊泽-学习中的苦与乐  时间:2022/12/12 19:41:46  对本文有异议

结论

同步还是异步,区别如下:

  • 同步:你使用 await 修饰符去调用一个异步(async)方法(是异步方法,不过是阻塞式的,可简单理解为同步);
  • 异步:你获取异步方法返回的 Task,就是异步(后文有代码示例);
  • 可以实现多任务执行顺序执行且不阻塞。

概述

async(C# 参考)

async 是“异步”的简写,使用 async 修饰符可将方法、lambda 表达式匿名方法指定为异步。

如果对方法或表达式使用此修饰符,则其称为异步方法 。

如下示例定义了一个名为 ExampleMethodAsync 的异步方法:

  1. public async Task<int> ExampleMethodAsync()
  2. {
  3. //...
  4. }

 

await(C# 参考)

await 运算符暂停对其所属的 async 方法的求值,直到其操作数表示的异步操作完成。

异步操作完成后,await 运算符将返回操作的结果(如果有)。

当 await 运算符应用到表示已完成操作的操作数时,它将立即返回操作的结果,而不会暂停其所属的方法。

 await 运算符不会阻止计算异步方法的线程。

当 await 运算符暂停其所属的异步方法时,控件将返回到方法的调用方。

官网说的话是不是听不明白?没关系,你就理解为添加了await 修饰符后,必须要等调用返回后才能继续执行下一步。

如下示例:

  1. public async Task<int> ExampleMethodAsync()
  2. {
  3. //...
  4. //这添加了await,执行到这里需要等待MethodAwiat方法执行完成后才会往下继续执行。
  5. int result = await MethodAwiat();
  6. //...
  7. }
  8. public async Task<int> MethodAwiat()
  9. {
  10. //...
  11. }

作用及基本用法

await和async可以简化我们异步编程,也可以让我们以一种类似同步编程的方式来进行异步编程。

另外当我们需要不阻塞主线程异步执行,但又要有顺序的执行相关代码的时候,await/async就可以排上用场。

基本用法如下示例:

  1. /// <summary>
  2. /// 可异步可同步
  3. /// </summary>
  4. /// <returns></returns>
  5. public async Task<string> TestAsync()
  6. {
  7. Thread.Sleep(3000);
  8. Task<string> task = new Task<string>(() =>
  9. {
  10. return "主程序返回后我还在执行数据:我是复杂的异步执行的方法,不阻碍主程序执行。。。。。";
  11. });
  12. task.Start();
  13. return await task;
  14. }
  15. // await 使得任务同步
  16. public async void T1()
  17. {
  18. // 使用 await 关键字,代表等待执行完成,同步
  19. string time = await TestAsync();
  20. Console.WriteLine(time);
  21. Console.WriteLine("执行完毕");
  22. }
  23. // 直接获得返回的 Task,实现异步
  24. public void T2()
  25. {
  26. // 获取 Task 任务对象,后面的逻辑过程可以弄成异步
  27. Task<string> task = TestAsync();
  28. // 这里可以处理其它事情,处理完毕后,再获取执行结果
  29. Console.WriteLine("执行完毕");
  30. Console.WriteLine(task.Result);
  31. }

 

实现多任务顺序执行且不阻塞

以微软文档的做早餐的案例加以简化来讲解 【使用Async和Await可以实现多任务顺序执行且不阻塞】。

主线任务任务:倒橙汁 -> 烤面包 -> 煎培根 -> 煎鸡蛋 -> 倒咖啡。

1.同步执行

我们任务逐步顺序执行如下,耗时:17064毫秒(17.064秒):

  1. using Microsoft.International.Converters.TraditionalChineseToSimplifiedConverter;
  2. using System;
  3. using System.Diagnostics;
  4. using System.Threading;
  5. namespace ConsoleApp1
  6. {
  7. class Program
  8. {
  9. static void Main(string[] args)
  10. {
  11. Stopwatch stopwatch = new Stopwatch();
  12. stopwatch.Start();
  13. PourOJ();
  14. PourCoffee();
  15. ToastBread();
  16. FryBacon();
  17. FryEggs();
  18. Console.WriteLine("早餐已经做完!");
  19. stopwatch.Stop();
  20. Console.WriteLine($"做早餐总计耗时:{stopwatch.ElapsedMilliseconds}");
  21. Console.ReadLine();
  22. }
  23. //倒橙汁
  24. private static void PourOJ()
  25. {
  26. Thread.Sleep(1000);
  27. Console.WriteLine("倒一杯橙汁");
  28. }
  29. //烤面包
  30. private static void ToastBread()
  31. {
  32. Console.WriteLine("开始烤面包");
  33. Thread.Sleep(3000);
  34. Console.WriteLine("烤面包好了");
  35. }
  36. //煎培根
  37. private static void FryBacon()
  38. {
  39. Console.WriteLine("开始煎培根");
  40. Thread.Sleep(6000);
  41. Console.WriteLine("培根煎好了");
  42. }
  43. //煎鸡蛋
  44. private static void FryEggs()
  45. {
  46. Console.WriteLine("开始煎鸡蛋");
  47. Thread.Sleep(6000);
  48. Console.WriteLine("鸡蛋好了");
  49. }
  50. //倒咖啡
  51. private static void PourCoffee()
  52. {
  53. Thread.Sleep(1000);
  54. Console.WriteLine("倒咖啡");
  55. }
  56. }
  57. }

 

2.并行执行

如果此时我们每一项任务都有一个单独的人去完成,将会缩短时间将近3倍(当然不能单纯的用时间量化他),

如下,耗时6041毫秒(6.041秒):

  1. using Microsoft.International.Converters.TraditionalChineseToSimplifiedConverter;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. namespace ConsoleApp1
  8. {
  9. class Program
  10. {
  11. static void Main(string[] args)
  12. {
  13. Test();
  14. Console.ReadLine();
  15. }
  16. private static void Test()
  17. {
  18. Stopwatch stopwatch = new Stopwatch();
  19. stopwatch.Start();
  20. List<Task> tasks = new List<Task>() { PourOJ(), ToastBread(), FryBacon(), FryEggs(), PourCoffee() };
  21. Task.WhenAll(tasks).ContinueWith((t) =>
  22. {
  23. Console.WriteLine("早餐已经做完!");
  24. stopwatch.Stop();
  25. Console.WriteLine($"做早餐总计耗时:{stopwatch.ElapsedMilliseconds}");
  26. });
  27. }
  28. //倒橙汁
  29. private static async Task PourOJ()
  30. {
  31. await Task.Delay(1000);
  32. Console.WriteLine("倒一杯橙汁");
  33. }
  34. //烤面包
  35. private static async Task ToastBread()
  36. {
  37. Console.WriteLine("开始烤面包");
  38. await Task.Delay(3000);
  39. Console.WriteLine("烤面包好了");
  40. }
  41. //煎培根
  42. private static async Task FryBacon()
  43. {
  44. Console.WriteLine("开始煎培根");
  45. await Task.Delay(6000);
  46. Console.WriteLine("培根煎好了");
  47. }
  48. //煎鸡蛋
  49. private static async Task FryEggs()
  50. {
  51. Console.WriteLine("开始煎鸡蛋");
  52. await Task.Delay(6000);
  53. Console.WriteLine("鸡蛋好了");
  54. }
  55. //倒咖啡
  56. private static async Task PourCoffee()
  57. {
  58. await Task.Delay(1000);
  59. Console.WriteLine("倒咖啡");
  60. }
  61. }
  62. }

 

3.并行且可指定顺序执行

但是我们不可能每次做早餐都有那么多人同时做,

需求变更:如果现在要求,先倒橙汁,然后倒咖啡,其余的操作并行执行,应该如何操作呢?

只需将以上案例的主线程Test 方法修改如下,其他的不变,耗时8073毫秒(8.073秒):

  1. private static async void Test()
  2. {
  3. Stopwatch stopwatch = new Stopwatch();
  4. stopwatch.Start();
  5. await PourOJ(); //倒橙汁
  6. await PourCoffee(); //然后倒咖啡
  7. List<Task> tasks = new List<Task>() { ToastBread(), FryBacon(), FryEggs() };//子任务List
  8. await Task.WhenAll(tasks); //其余的并行操作
  9. Console.WriteLine("早餐已经做完!");
  10. stopwatch.Stop();
  11. Console.WriteLine($"做早餐总计耗时:{stopwatch.ElapsedMilliseconds}");
  12. }

总结

我们发现,用好了async和await确实很节省时间。

大家可以想想怎么优雅的在异步里面开多线程(多主线程多子线程)最节省时间。

参考文献

 


 

喜欢就点赞加关注。

欢迎关注订阅微信公众号【熊泽有话说】,更多好玩易学知识等你来取
作者:熊泽-学习中的苦与乐
公众号:熊泽有话说

QQ群:711838388
出处:https://www.cnblogs.com/xiongze520/p/16976940.html
您可以随意转载、摘录,但请在文章内注明作者和原文链接。  

 

 

原文链接:https://www.cnblogs.com/xiongze520/p/16976940.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号