[C#] 走进异步编制程序的世界 – 解析异步方法(上)

走进异步编制程序的世界 – 深入分析异步方法(上)

  那是上篇《走进异步编制程序的社会风气 – 开端接触 async/await
异步编制程序
》(入门)的第三章内容,重倘若与我们一块儿深远斟酌下异步方法。

  本文供给通晓委托的使用。

ca88官网, 

目录

 

介绍异步方法

     异步方法:在执行到位前及时回去调用方法,在调用方法继续实行的历程中变成职分。

     语法剖析:

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

     (二)需求:包含N(N>0) 个 await 表达式(不设有 await 表达式的话 IDE
会发出警告),表示需求异步施行的职务。【备注】感激 czcz1024 的校勘与增加补充:未有的话,就和一般方法一致进行了。

     (三)重临类型:只可以回去 三种等级次序(void、Task 和 Task<T>)。Task 和 Task<T>
标记重返的靶子会在今后做到专业,表示调用方法和异步方法能够继续施行。

     (四)参数:数量不限。但不可能运用 out
和 ref 关键字。

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

     (陆)别的:匿超级模特式和 Lambda
表达式也能够看做异步对象;async 是贰个上下文关键字;关键字 async
必须在回到类型前。

 

ca88官网 1图1异步方法的大约结构图

  关于 async 关键字:

  壹在重返类型以前包罗 async 关键字

  2它只是标志该格局包罗3个或八个 await
表明式,即,它本人不创立异步操作。

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

 

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

  (一)Task<T>:调用方法要从调用中获得二个T 类型的值,异步方法的回来类型就无法不是Task<T>。调用方法从 Task 的
Result 属性获取的就是 T 类型的值。

ca88官网 2ca88官网 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

ca88官网 4ca88官网 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 

ca88官网 6

图2

ca88官网 7

图3

 

  (2)Task:调用方法没有需求从异步方法中取重返值,不过希望检查异步方法的情形,那么能够选取可以回到
Task 类型的靶子。可是,即使异步方法中包蕴 return
语句,也不会回来任刘瑞芳西。

ca88官网 8ca88官网 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

ca88官网 10ca88官网 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

 

ca88官网 12

 

图4

ca88官网 13

图5

     

  (三)void:调用方法实践异步方法,但又无需做进一步的相互。 

ca88官网 14ca88官网 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

ca88官网 16ca88官网 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

ca88官网 18

图6

ca88官网 19

图7

 

一、控制流

     异步方法的构造可拆分成几个例外的区域:

     (壹)表达式以前的1部分:从点子头到第三个await 表达式之间的装有代码。

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

     (三)表明式之后的片段:await
表达式的接二连三部分。

 ca88官网 20

  图1-1

 

  该异步方法试行流程:从await表明式在此之前的地点开始,同步实践到第一个await,标志着第贰部分进行完成,一般的话此时 await 工作还没成功。当await
职分成功后,该办法将一连联合实践后续部分。在实施的一而再部分中,要是仍旧留存
await,就再也上述进度。

  当达到 await
表明式时,线程将从异步方法重返到调用方法。假诺异步方法的回来类型为 Task
或 Task<T>,会创建三个 Task 对象,标记必要异步完毕的职分,然后将
Task 重返来调用方法。

 

ca88官网 21

  图1-2

  异步方法的调整流:

  一异步试行 await 表明式的闲暇任务。

  二await 表达式实践到位,继续实施后续部分。如再遭受 await
表明式,按一样情况开始展览拍卖。

  3达到末尾或遭遇 return 语句时,依据再次回到类型能够分二种境况:

    a.void:退出调节流。

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

    c.Task<T>:设置 Task
的性质和重临值(Result 属性)并脱离。

  4还要,调用方法将继续推行,从异步方法赢得 Task
对象。要求值的时候,会中断等到 Task 对象的 Result
属性被赋值才会继续实行。

 

  【难点】

  1首先次相遇 await
所重返对象的等级次序。这一个再次回到类型正是一齐方法头的归来类型,跟 await
表达式的重返值未有关系。

  2达到异步方法的终极或境遇 return
语句,它并从未真的的归来1个值,而是退出了该方式。

 

二、await 表达式

  await 表明式钦点了2个异步实施的天职。暗许意况,该职分在当下线程异步实施。

  每贰个职务正是二个 awaitable 类的实例。awaitable 类型指包含GetAwaiter() 方法的品种。

  实际上,你并不供给营造筑组织调的 awaitable,一般只须求动用 Task
类,它便是 awaitable。

  最简易的主意是在格局中使用
Task.Run() 来创立一个 Task。【注意】它是在不一致的线程上实施措施。

 

  让我们一并来看望示例。

ca88官网 22ca88官网 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

ca88官网 24

图2-1

ca88官网 25

图2-2

   下面 肆 个 Task.Run() 都以运用了 Task Run(Func<TReturn> func)
情势来一贯或直接调用 Guid.NewGuid()。

 

  Task.Run() 帮助 4 中不一致的信托项目所代表的艺术:Action、Func<TResult>、Func<Task>
和 Func<Task<TResult>>

ca88官网 26ca88官网 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

ca88官网 28

图2-三 Task.Run() 方法的重载

 

三、How 撤销异步操作

   CancellationToken 和 CancellationTokenSource
那多个类允许你截止执行异步方法。

  (一)CancellationToken
对象涵盖职分是还是不是被撤消的新闻;假如该对象的性质 IsCancellationRequested

true,任务需终止操作并重临;该对象操作是不可逆的,且只好利用(修改)三遍,即该目的内的 IsCancellationRequested
属性被安装后,就不可能改造。

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

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

 

  示例

ca88官网 29ca88官网 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

ca88官网 31

图3-1

ca88官网 32

图三-2 注释两行代码

ca88官网 33

图三-三:图三-壹和图叁-2的施行结果(注释两行代码)

  上海教室是不调用 Cancel() 方法的结果图,不会收回职务的试行。

 

  下图在 三 秒后调用 Cancel() 方法打消义务的施行:

ca88官网 34

图3-四:去掉注释

ca88官网 35

图三-伍:图3-一和图三-四的实践结果(去掉注释)

 

小结

  • 介绍异步方法的语法、二种分裂的回来值类型(void、Task 和
    Task<T>)和操纵流程等。
  • 简简单单常用的异步实践办法:Task.Run()。【注意】它是在区别的线程上实施措施。
  • 如何撤销异步操作。

 

传送门

  入门:《开端接触 async/await
异步编程

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

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

 


原稿链接:http://www.cnblogs.com/liqingwen/p/5844095.html

 【参考】《Illustrated C# 2012》

相关文章