[C#] 走进异步编制程序的世界 – 开头接触 async/await

一、What’s 异步?

     运维程序时,系统会在内部存款和储蓄器中创制一个新的历程。进度是组成运营程序财富的聚合。

     在经过之中,有号称线程的基石对象,它象征的是当真的实施顺序。系统会在 Main
方法的率先行语句就从头线程的实行。

 

     线程:

     ①暗许气象,多个进程只含有二个线程,从程序的初步到实施实现;

   
 ②线程能够派生自别的线程,所以二个经过能够包括差异景观的多个线程,来举行顺序的分化部分;

     ③1个进度中的八个线程,将共享该进程的能源;

     ④系统为总计机执行所布置的单元是线程,而非进度。

 

   
 一般的话大家写的控制台程序都只使用了1个线程,从第叁条语句按梯次执行到终极一条。但在不少的景色下,那种回顾的模子会在品质或用户体验上欠好。

   
 例如:服务器要同时处理来自多少个客户端程序的请求,又要等待数据库和此外设备的响应,那将严重影响属性。程序不应有将时刻浪费在响应上,而要在等候的同时实施此外职务!

   
 未来我们初阶进入异步编制程序。在异步程序中,代码不需求依据编写时的顺序执行。那时大家必要用到
C# 5.0 引入的 async/await 来营造异步方法。

 

     我们先看一下不用异步的演示:

 1     class Program
 2     {
 3         //创建计时器
 4         private static readonly Stopwatch Watch = new Stopwatch();
 5 
 6         private static void Main(string[] args)
 7         {
 8             //启动计时器
 9             Watch.Start();
10 
11             const string url1 = "http://www.cnblogs.com/";
12             const string url2 = "http://www.cnblogs.com/liqingwen/";
13 
14             //两次调用 CountCharacters 方法(下载某网站内容,并统计字符的个数)
15             var result1 = CountCharacters(1, url1);
16             var result2 = CountCharacters(2, url2);
17 
18             //三次调用 ExtraOperation 方法(主要是通过拼接字符串达到耗时操作)
19             for (var i = 0; i < 3; i++)
20             {
21                 ExtraOperation(i + 1);
22             }
23 
24             //控制台输出
25             Console.WriteLine($"{url1} 的字符个数:{result1}");
26             Console.WriteLine($"{url2} 的字符个数:{result2}");
27 
28             Console.Read();
29         }
30 
31         /// <summary>
32         /// 统计字符个数
33         /// </summary>
34         /// <param name="id"></param>
35         /// <param name="address"></param>
36         /// <returns></returns>
37         private static int CountCharacters(int id, string address)
38         {
39             var wc = new WebClient();
40             Console.WriteLine($"开始调用 id = {id}:{Watch.ElapsedMilliseconds} ms");
41 
42             var result = wc.DownloadString(address);
43             Console.WriteLine($"调用完成 id = {id}:{Watch.ElapsedMilliseconds} ms");
44 
45             return result.Length;
46         }
47 
48         /// <summary>
49         /// 额外操作
50         /// </summary>
51         /// <param name="id"></param>
52         private static void ExtraOperation(int id)
53         {
54             //这里是通过拼接字符串进行一些相对耗时的操作
55             var s = "";
56 
57             for (var i = 0; i < 6000; i++)
58             {
59                 s += i;
60             }
61 
62             Console.WriteLine($"id = {id} 的 ExtraOperation 方法完成:{Watch.ElapsedMilliseconds} ms");
63         }
64     }

图片 1

     图1-1 运维的职能图,以皮秒(ms)为单位

 

  【备注】一般的话,直接拼接字符串是一种相比耗质量的手法,借使对字符串拼接有总体性要求的话应该使用
StringBuilder。

  【注意】每回运转的结果也许两样。不管哪次调节和测试,绝超过一半时日都浪费前四回调用(CountCharacters
方法),即在等候网站的响应上。

 

图片 2

  图1-2
依照实施结果所画的岁月轴

 

     有人曾幻想着这么进步品质的章程:在调用 A
方法时,不等它执行完,直接实施 B 方法,然后等 A 方法执行到位再处理。

     C# 的 async/await 就能够允许大家这么弄。

图片 3图片 4

 1     class Program
 2     {
 3         //创建计时器
 4         private static readonly Stopwatch Watch = new Stopwatch();
 5 
 6         private static void Main(string[] args)
 7         {
 8             //启动计时器
 9             Watch.Start();
10 
11             const string url1 = "http://www.cnblogs.com/";
12             const string url2 = "http://www.cnblogs.com/liqingwen/";
13 
14             //两次调用 CountCharactersAsync 方法(异步下载某网站内容,并统计字符的个数)
15             Task<int> t1 = CountCharactersAsync(1, url1);
16             Task<int> t2 = CountCharactersAsync(2, url2);
17 
18             //三次调用 ExtraOperation 方法(主要是通过拼接字符串达到耗时操作)
19             for (var i = 0; i < 3; i++)
20             {
21                 ExtraOperation(i + 1);
22             }
23 
24             //控制台输出
25             Console.WriteLine($"{url1} 的字符个数:{t1.Result}");
26             Console.WriteLine($"{url2} 的字符个数:{t2.Result}");
27 
28             Console.Read();
29         }
30 
31         /// <summary>
32         /// 统计字符个数
33         /// </summary>
34         /// <param name="id"></param>
35         /// <param name="address"></param>
36         /// <returns></returns>
37         private static async Task<int> CountCharactersAsync(int id, string address)
38         {
39             var wc = new WebClient();
40             Console.WriteLine($"开始调用 id = {id}:{Watch.ElapsedMilliseconds} ms");
41 
42             var result = await wc.DownloadStringTaskAsync(address);
43             Console.WriteLine($"调用完成 id = {id}:{Watch.ElapsedMilliseconds} ms");
44 
45             return result.Length;
46         }
47 
48         /// <summary>
49         /// 额外操作
50         /// </summary>
51         /// <param name="id"></param>
52         private static void ExtraOperation(int id)
53         {
54             //这里是通过拼接字符串进行一些相对耗时的操作
55             var s = "";
56 
57             for (var i = 0; i < 6000; i++)
58             {
59                 s += i;
60             }
61 
62             Console.WriteLine($"id = {id} 的 ExtraOperation 方法完成:{Watch.ElapsedMilliseconds} ms");
63         }
64     }

那是修改后的代码

图片 5

 图1-3 修改后的实行结果图

图片 6

图1-4 依据加入异步后的推行结果画的日子轴。

 

  大家观看时间轴发现,新版代码比旧版快了重重(由于网络波动的原故,很大概晤面世耗费时间比从前长的情状)。那是由于
ExtraOperation 方法的数13回调用是在
CountCharactersAsync 方法调用时等待响应的进程中开始展览的。全部的劳作都以在主线程中做到的,没有创设新的线程。

 

  【改动分析】只改了多少个细节的地点,直接进行代码的话恐怕看不出来,改动如下:

   图片 7

 图1-5

图片 8

  图1-6

 

  ①从 Main 方法执行到 CountCharactersAsync(1, url1)
方法时,该方法会即刻回到,然后才会调用它当中的方法起先下载内容。该办法重临的是八个Task<int>
类型的占位符对象,表示布置展开的干活。那么些占位符最后会重返 int
类型的值。

  ②如此就能够不要等 CountCharactersAsync(1, url1)
方法执行到位就足以继承拓展下一步操作。到实践 CountCharactersAsync(2,
url2)  方法时,跟 ① 一样再次回到 Task<int> 对象。

  ③然后,Main 方法继续执行3回 ExtraOperation
方法,同时一次 CountCharactersAsync 方法依然在持续工作 。

  ④t1.Result 和 t2.Result 是指从 CountCharactersAsync 方法调用的
Task<int>
对象取结果,如果还未曾结果的话,将封堵,直有结果回到结束。

 

目录

 

解析异步方法(上)](http://www.cnblogs.com/liqingwen/p/5844095.html)》《[走进异步编程的世界

剖析异步方法(下)](http://www.cnblogs.com/liqingwen/p/5866241.html)》

  后篇:《走进异步编制程序的世界 – 在 GUI
中施行异步操作

 


本文首联:http://www.cnblogs.com/liqingwen/p/5831951.html

【参考】《Illustrated C# 2012》

传送门

  下篇:《[走进异步编制程序的社会风气 –

 ③ 、What’s 异步方法

     异步方法:在举办到位前及时回到调用方法,在调用方法继续执行的进度中成功职分。

     语法分析:

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

     (2)供给:包括N(N>0) 个 await 表明式(不存在 await 表达式的话 IDE
会发出警示),表示要求异步执行的义务。

     (3)再次来到类型:只好回到 3
类别型(void、Task 和 Task<T>)。Task 和 Task<T>
标识再次来到的目的会在今后完成工作,表示调用方法和异步方法能够继续执行。

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

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

     (6)别的:匿名格局和 Lambda
表达式也能够作为异步对象;async 是1个上下文关键字;关键字 async
必须在重回类型前。

 图片 9

图3-1 异步方法的简练结构图

 

小结

  1.剖析了经过和线程的定义

  2.异步的简便用法

  3.async/await 结构体

  4.异步方塞尔维亚语法结构

 

二、async/await 结构

     先解析一下专业名词:

     同步方法:3个主次调用某些方法,等到其进行到位现在才实行下一步操作。那也是暗许的款型。

     异步方法:三个先后调用有些方法,在处理完了从前就重临该方法。通过
async/await 大家就足以兑现那体系型的格局。

 

     async/await 结构可分为三部分:

     (1)调用方法:该方法调用异步方法,然后在异步方法执行其任务的时候继续执行;

     (2)异步方法:该办法异步执行工作,然后立刻回去到调用方法;

     (3)await
表明式:用于异步方法内部,提议供给异步执行的天职。多少个异步方法能够涵盖多少个await 表明式(不设有 await 表达式的话 IDE 会发出警告)。

 

  现在我们来分析一下示范。

图片 10

  图2-1

 

  这是读书异步编制程序的入门篇。

  涉及 C# 5.0 引入的 async/await,但在决定台出口示例时平时会动用 C#
6.0 的 $”” 来拼接字符串,相当于string.Format() 方法。

 

走进异步编制程序的社会风气 – 初阶接触 async/await

 

相关文章