澳门新萄京 35

剖析异步方法【澳门新萄京】

走进异步编程的世界 – 解析异步方法(上)

  那是上篇《走进异步编制程序的世界 – 初叶接触 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)别的:无名氏方式和 拉姆da
表明式也得以视作异步对象;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,标记着第4盘部举办实现,常常的话此时 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()。

 

  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() 方法的重载

 

三、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》

发表评论

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