在调用方法继续实行的进度中达成职责

走进异步编制程序的社会风气 – 分析异步方法(上)

  那是上篇《走进异步编程的世界 – 最先接触 async/await
异步编制程序》(入门)的第二章内容,主假若与大家一起深刻研讨下异步方法。

  本文须要掌握委托的使用。

 

目录

  • 介绍异步方法

  • 控制流

  • await
    表达式

  • How
    废除异步操作

 

介绍异步方法

     异步方法:在奉行到位前及时回去调用方法,在调用方法继续实践的进程中成功职分。

     语法解析:

     (1)关键字:方法头使用 async
修饰。

     (2)必要:包括N(N>0) 个 await 表明式(不设有 await 表明式的话 IDE
会发出警告),表示需求异步推行的任务。【备注】感激 czcz1024 的订正与增加补充:未有的话,就和日常方法豆蔻梢头致举办了。

     (3)再次回到类型:只可以回去 3
种档案的次序(void、Task 和 Task<T>)。Task 和 Task<T>
标志再次来到的靶子会在未来成功专门的学问,表示调用方法和异步方法能够继续试行。

     (4)参数:数量不限。但不能够应用 out
和 ref 关键字。

     (5)命名约定:方法后缀名应以 Async
结尾。

     (6)其余:匿超级模特式和 Lambda
表明式也得以充当异步对象;async 是二个上下文关键字;关键字 async
必得在回来类型前。

 

图片 1图1
异步方法的精简布局图

  关于 async 关键字:

  ①在回到类型从前包括 async 关键字

  ②它只是标志该形式包罗一个或多个 await
表明式,即,它自个儿不成立异步操作。

  ③它是上下文关键字,就可以作为变量名。

 

  未来先来回顾深入深入分析一下那三种回到值类型:void、Task 和 Task<T>

  (1)Task<T>:调用方法要从调用中拿走三个T 类型的值,异步方法的归来类型就必需是Task<T>。调用方法从 Task 的
Result 属性获取的正是 T 类型的值。

图片 2图片 3

 1         private static void Main(string[] args)
 2         {
 3             Task<int> t = Calculator.AddAsync(1, 2);
 4 
 5             //一直在干活
 6 
 7             Console.WriteLine($"result: {t.Result}");
 8 
 9             Console.Read();
10         }

Program.cs

图片 4图片 5

 1     internal class Calculator
 2     {
 3         private static int Add(int n, int m)
 4         {
 5             return n + m;
 6         }
 7 
 8         public static async Task<int> AddAsync(int n, int m)
 9         {
10             int val = await Task.Run(() => Add(n, m));
11 
12             return val;
13         }
14     }

View Code 

图片 6

图2

图片 7

图3

 

  (2)Task:调用方法不需求从异步方法中取重临值,不过指望检查异步方法的情景,那么能够挑选能够回到
Task 类型的指标。不过,固然异步方法中包蕴 return
语句,也不会回来任李良华西。

图片 8图片 9

 1         private static void Main(string[] args)
 2         {
 3             Task t = Calculator.AddAsync(1, 2);
 4 
 5             //一直在干活
 6 
 7             t.Wait();
 8             Console.WriteLine("AddAsync 方法执行完成");
 9 
10             Console.Read();
11         }

Program.cs

图片 10图片 11

 1     internal class Calculator
 2     {
 3         private static int Add(int n, int m)
 4         {
 5             return n + m;
 6         }
 7 
 8         public static async Task AddAsync(int n, int m)
 9         {
10             int val = await Task.Run(() => Add(n, m));
11             Console.WriteLine($"Result: {val}");
12         }
13     }

View Code

 

图片 12

 

图4

图片 13

图5

     

  (3)void:调用方法试行异步方法,但又无需做越来越的相互。 

图片 14图片 15

 1         private static void Main(string[] args)
 2         {
 3             Calculator.AddAsync(1, 2);
 4 
 5             //一直在干活
 6 
 7             Thread.Sleep(1000); //挂起1秒钟
 8             Console.WriteLine("AddAsync 方法执行完成");
 9 
10             Console.Read();
11         }

Program.cs

图片 16图片 17

 1     internal class Calculator
 2     {
 3         private static int Add(int n, int m)
 4         {
 5             return n + m;
 6         }
 7 
 8         public static async void AddAsync(int n, int m)
 9         {
10             int val = await Task.Run(() => Add(n, m));
11             Console.WriteLine($"Result: {val}");
12         }
13     }

Calculator.cs

图片 18

图6

图片 19

图7

 

一、控制流

     异步方法的布局可拆分成八个例外的区域:

     (1)表明式以前的有个别:从点子头到第二个await 表明式之间的持有代码。

     (2)await
表明式:将被异步施行的代码。

     (3)表明式之后的有个别:await
表明式的接轨部分。

 图片 20

  图1-1

 

  该异步方法实行流程:从await表明式此前之处最早,同步实践到第三个await,标志着第一片段实行完结,通常的话这时候 await 职业尚未达成。当await
义务成功后,该格局将三翻五次联手实践后续部分。在进行的一而再部分中,假如照旧存在
await,就重新上述进程。

  当达到 await
表明式时,线程将从异步方法重临到调用方法。假如异步方法的回来类型为 Task
或 Task<T>,会创建一个 Task 对象,标记须求异步达成的职务,然后将
Task 重回来调用方法。

 

图片 21

  图1-2

  异步方法的调控流:

  ①异步试行 await 表明式的空余任务。

  ②await 表明式推行到位,继续推行后续部分。如再遇上 await
表达式,按相仿情状张开管理。

  ③达到末尾或遇到 return 语句时,依照再次回到类型能够分二种情状:

    a.void:退出调整流。

    b.Task:设置
Task 的性质并退出。

    c.Task<T>:设置 Task
的品质和再次来到值(Result 属性)并退出。

  ④何况,调用方法将继续实行,从异步方法获得 Task
对象。须要值的时候,会暂停等到 Task 对象的 Result
属性被赋值才会继续试行。

 

  【难点】

  ①先是次遇上 await
所再次回到对象的类型。这么些重回类型正是意气风发道方法头的回来类型,跟 await
表明式的再次回到值未有关系。

  ②达到异步方法的结尾或碰着 return
语句,它并不曾真正的回来贰个值,而是退出了该方法。

 

二、await 表达式

  await 表达式钦定了二个异步实行的职分。默许景况,该职务在最近线程异步推行。

  每四个职分正是二个 awaitable 类的实例。awaitable 类型指包涵GetAwaiter(卡塔尔 方法的品类。

  实际上,你并没有供给创设和睦的 awaitable,平时只须要运用 Task
类,它正是 awaitable。

  最简便易行的点子是在章程中动用
Task.Run(卡塔尔国 来创设二个 Task。【注意】它是在差别的线程上进行措施。

 

  让我们一同来看看示例。

图片 22图片 23

 1     internal class Program
 2     {
 3         private static void Main(string[] args)
 4         {
 5             var t = Do.GetGuidAsync();
 6             t.Wait();
 7 
 8             Console.Read();
 9         }
10 
11 
12         private class Do
13         {
14             /// <summary>
15             /// 获取 Guid
16             /// </summary>
17             /// <returns></returns>
18             private static Guid GetGuid()   //与Func<Guid> 兼容
19             {
20                 return Guid.NewGuid();
21             }
22 
23             /// <summary>
24             /// 异步获取 Guid
25             /// </summary>
26             /// <returns></returns>
27             public static async Task GetGuidAsync()
28             {
29                 var myFunc = new Func<Guid>(GetGuid);
30                 var t1 = await Task.Run(myFunc);
31 
32                 var t2 = await Task.Run(new Func<Guid>(GetGuid));
33 
34                 var t3 = await Task.Run(() => GetGuid());
35 
36                 var t4 = await Task.Run(() => Guid.NewGuid());
37 
38                 Console.WriteLine($"t1: {t1}");
39                 Console.WriteLine($"t2: {t2}");
40                 Console.WriteLine($"t3: {t3}");
41                 Console.WriteLine($"t4: {t4}");
42             }
43         }
44     }

View Code

图片 24

图2-1

图片 25

图2-2

   上边 4 个 Task.Run(卡塔尔国 都以接受了 Task Run(Func<TReturn> func卡塔尔情势来直接或直接调用 Guid.NewGuid(卡塔尔(英语:State of Qatar)。

 

  Task.Run(卡塔尔国 辅助 4 中分歧的嘱托项目所表示的艺术:Action、Func<TResult>、Func<Task>
和 Func<Task<TResult>>

图片 26图片 27

 1     internal class Program
 2     {
 3         private static void Main(string[] args)
 4         {
 5             var t = Do.GetGuidAsync();
 6             t.Wait();
 7 
 8             Console.Read();
 9         }
10 
11         private class Do
12         {
13             public static async Task GetGuidAsync()
14             {
15                 await Task.Run(() => { Console.WriteLine(Guid.NewGuid()); });   //Action
16 
17                 Console.WriteLine(await Task.Run(() => Guid.NewGuid()));    //Func<TResult>
18 
19                 await Task.Run(() => Task.Run(() => { Console.WriteLine(Guid.NewGuid()); }));   //Func<Task>
20 
21                 Console.WriteLine(await Task.Run(() => Task.Run(() => Guid.NewGuid())));    //Func<Task<TResult>>
22             }
23         }
24     }

View Code

图片 28

图2-3 Task.Run(卡塔尔(英语:State of Qatar) 方法的重载

 

三、How 撤除异步操作

   CancellationToken 和 CancellationTokenSource
那多个类允许你结束施行异步方法。

  (1)CancellationToken
对象包含义务是不是被撤消的消息;倘使该目的的质量 IsCancellationRequested

true,职务需终止操作并重回;该对象操作是不可逆的,且不能不利用(修改)一次,即该对象内的 IsCancellationRequested
属性被设置后,就无法改过。

  (2)CancellationTokenSource 可创造 CancellationToken
对象,调用 CancellationTokenSource 对象的 Cancel
方法,会使该指标的 CancellationToken 属性 IsCancellationRequested 设置为
true。

  【注意】调用 CancellationTokenSource
对象的 Cancel
方法,并不会推行撤除操作,而是会将该目的的 CancellationToken
属性 IsCancellationRequested 设置为 true。

 

  示例

图片 29图片 30

 1     internal class Program
 2     {
 3         private static void Main(string[] args)
 4         {
 5             CancellationTokenSource source = new CancellationTokenSource();
 6             CancellationToken token = source.Token;
 7 
 8             var t = Do.ExecuteAsync(token);
 9 
10             //Thread.Sleep(3000);   //挂起 3 秒
11             //source.Cancel();    //传达取消请求
12 
13             t.Wait(token);  //等待任务执行完成
14             Console.WriteLine($"{nameof(token.IsCancellationRequested)}: {token.IsCancellationRequested}");
15 
16             Console.Read();
17         }
18 
19 
20     }
21 
22     internal class Do
23     {
24         /// <summary>
25         /// 异步执行
26         /// </summary>
27         /// <param name="token"></param>
28         /// <returns></returns>
29         public static async Task ExecuteAsync(CancellationToken token)
30         {
31             if (token.IsCancellationRequested)
32             {
33                 return;
34             }
35 
36             await Task.Run(() => CircleOutput(token), token);
37         }
38 
39         /// <summary>
40         /// 循环输出
41         /// </summary>
42         /// <param name="token"></param>
43         private static void CircleOutput(CancellationToken token)
44         {
45             Console.WriteLine($"{nameof(CircleOutput)} 方法开始调用:");
46 
47             const int num = 5;
48             for (var i = 0; i < num; i++)
49             {
50                 if (token.IsCancellationRequested)  //监控 CancellationToken
51                 {
52                     return;
53                 }
54 
55                 Console.WriteLine($"{i + 1}/{num} 完成");
56                 Thread.Sleep(1000);
57             }
58         }
59     }

View Code

图片 31

图3-1

图片 32

图3-2 注释两行代码

图片 33

图3-3:图3-1和图3-2的奉行结果(注释两行代码)

  上海教室是不调用 Cancel(卡塔尔(قطر‎ 方法的结果图,不会吊销任务的履行。

 

  下图在 3 秒后调用 Cancel(卡塔尔 方法撤废任务的试行:

图片 34

图3-4:去掉注释

图片 35

图3-5:图3-1和图3-4的施行结果(去掉注释)

 

小结

  • 介绍异步方法的语法、二种不一致的回到值类型(void、Task 和
    Task<T>)和决定流程等。
  • 大致常用的异步试行办法:Task.Run(卡塔尔(قطر‎。【注意】它是在分裂的线程上施行方式。
  • 怎么废除异步操作。

 

传送门

  入门:《发端接触 async/await
异步编制程序》

  补充篇:《走进异步编制程序的世界 –
解析异步方法(下)》

  GUI 篇:《走进异步编程的社会风气 – 在 GUI
中实践异步操作》

 


初藳链接:

 【参考】《Illustrated C# 2012》

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website