【亚洲必赢官网】有关异步执行,常见的异步方式async

前边研讨过c#的async和await关键字,幕后干了怎么,但是不知道为何找不到有关质地了。今后再一次研究一回,顺便记录下来,方便未来翻看。

原稿地址: 

[.NET] 利用 async & await 的异步编制程序,.net利用async

行使 async & await 的异步编制程序

【博主】反骨仔    【出处】   

基础知识

async
关键字标可瑞康个措施,该方法再次回到值是二个Task、也许Task<TResult>、void、包涵GetAwaiter方法的档次。该办法一般包涵多少个await表明式。该表明式标注2个点,将被有个别异步方法回跳到该点。并且,当前函数执行到该点,将立刻回去控制权给调用方。

上述描述了async方法想干的事情,至于何以落实,那里就不读书了。

 

采纳 async & await 的异步编制程序

【博主】反骨仔    【出处】   

目录

  • 异步编制程序的简介
  • 异步提升响应能力
  • 更便于编写的异步方法
  • 异步方法的控制流(核心)
  • 异步中的线程
  • async 和 await
    修饰符
  • 归来类型和参数音信
  • 取名的预定

 

个人见解

通过能够领略,async
和await关键字主要目标是为了操纵异步线程的一块,让1个异步进度,表现得就像一块进度一样。

比如说async
方法分n个职务去下载网页并开始展览处理:先await下载,然后登时回去调用方,之后的处理就由异步线程达成下载后调用。这时候调用方能够继续执行它的职务,但是,假使调用方登时就供给async的结果,那么应该就只好等待,可是多数情景:他一时半刻不要求以此结果,那么就能够并行处理那几个代码。

可知,并行性显示在await 上,借使await
点和末段的数额结果偏离越远,那么并行度就越高。若是await的点越多,相信也会改正并行性。

资料展现,async 和await
关键字并不会创立线程,那是很关键的有个别。
她们只是创制了二个回来点,提须要必要她的线程使用。那么线程终归是哪个人创造?注意await
表达式的三结合,他供给叁个Task,一个Task并不意味一定要开创线程,也能够是另三个async方法,然则层层包裹最中间的主意,很恐怕正是3个原生的Task,比如await
Task.Run(()=>Thread.Sleep(0));
,那个确实爆发线程的说话,就会依据前边那多少个await点,各个回调。

从那点来看,async
方法,未必便是叁个异步方法,他在语义上尤其贴近“非阻塞”,
当遇到阻塞操作,马上用await确定地点再次回到,至于别的更深一层的缓解手段,它就不关切了。那是程序员须要关怀的,程序员需求用真的的始建线程代码,来形成异步操作(当然这一步可由库程序员达成)。

瞩目async的多少个返回值类型,那代表了分歧的行使情况。假如是void,表明客户端不拥戴数据同步难点,它只须要线程的控制权立刻回去。能够用在ui
等场所,如若是Task,客户端也不尊敬数据,可是它愿意能够控制异步线程,那大概是对职务执行顺序有必然的供给。当然,最广泛的是Task<TResult>。

综上,async和await并不是为了多职责而设计的,如若追求高产出,应该在async函数内部用Task好好陈设一番。在行使async
和await的时候,只供给遵照非阻塞的笔触去编写代码就能够了,至于幕后怎么处理就付出真正的多线程代码创制者吧。

一块编制程序与异步编制程序

普普通通状态下,大家写的C#代码正是一起的,运转在同1个线程中,从程序的第①行代码到最后一句代码顺序执行。而异步编程的宗旨是接纳二十八线程,通过让不相同的线程执行分歧的任务,达成不一样代码的竞相运维。

目录

  • 异步编程的简介
  • 异步升高响应能力
  • 更易于编写的异步方法
  • 异步方法的控制流(主题)
  • 线程
  • async 和 await
  • 重返类型和参数新闻
  • 取名的预订

 

① 、异步编程的简介

  通过行使异步编制程序,你可避防止品质瓶颈并提升你的应用程序的完好响应能力。

  从
VS 2011 起头,新引入了一个简化的法门,称为异步编制程序。大家在 >= .NET
4.5 如月 Windows 运维时中采用异步,编写翻译器它会赞助了我们下落了已经进行的高难度异步代码编写的办事,但逻辑结构却就像是于一块代码。由此,大家仅供给开始展览一小部分编制程序的干活就足以博得异步编制程序的拥有优点。

 

示范代码

        static async Task RunTaskAsync(int step)
        {
            for(int i=0; i < step; i++)
            {
                await Task.Run(()=>Thread.Sleep(tmloop));//点是静态的,依次执行
                Thread.Sleep(tm2);
            }
            Thread.Sleep(tm3);
        }

//客户端
            Task tk= RunTaskAsync(step);
            Thread.Sleep(tm1);//这一段是并行的,取max(函数,代码段)最大时间
            tk.Wait( );//这里代表最终数据

为了完结可观并行,应该用真的的四线程代码:

        static async Task RunTaskByParallelAsync(int step)
        {
            await Task.Run(()=>Parallel.For(0,step,
                s=>{loop(tmloop);
                    loop(tm2);
                    }
            ));
            loop(tm3);
        }

前台线程与后台线程

至于二十多线程,早在.NET2.0时代,基础类库中就提供了Thread达成。默许景况下,实例化二个Thread创造的是前台线程,只要有前台线程在运行,应用程序的历程就平昔处在运维状态,以控制台应用程序为例,在Main方法中实例化3个Thread,这么些Main方法就会等待Thread线程执行达成才脱离。而对于后台线程,应用程序将不考虑其是或不是履行完结,只要应用程序的主线程和前台线程执行完结就能够脱离,退出后有着的后台线程将被活动终止。来看代码应该更清楚部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
 
namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("主线程开始");
 
            //实例化Thread,默认创建前台线程
            Thread t1 = new Thread(DoRun1);
            t1.Start();
 
            //可以通过修改Thread的IsBackground,将其变为后台线程
            Thread t2 = new Thread(DoRun2) { IsBackground = true };
            t2.Start();
 
            Console.WriteLine("主线程结束");
        }
 
        static void DoRun1()
        {
            Thread.Sleep(500);
            Console.WriteLine("这是前台线程调用");
        }
 
        static void DoRun2()
        {
            Thread.Sleep(1500);
            Console.WriteLine("这是后台线程调用");
        }
    }
}

运转方面包车型大巴代码,能够看看DoRun2方法的打字与印刷音信“那是后台线程调用”将不会被出示出来,因为应用程序执行完主线程和前台线程后,就活动退出了,全体的后台线程将被活动终止。那里后台线程设置了等候1.5s,假如这一个后台线程比前台线程或主线程提前实施完结,对应的音信“那是后台线程调用”将能够被成功打印出来。

【亚洲必赢官网】有关异步执行,常见的异步方式async。① 、异步编程的简介

  通过使用异步编制程序,你能够制止品质瓶颈并增强应用程序的共同体响应能力。

  Visual
Studio 二零一一 引入了一个简化的艺术,异步编制程序,在 .NET Framework 4.5 和
Windows 运维时行使异步扶助。编译器可实施开发职员曾展开的高难度工作,且应用程序保留了贰个像样于联合代码的逻辑结构。由此,您仅必要开始展览一小部分做事就能够赢得异步编制程序的有所优点。

 

贰 、异步进步响应能力

  异步对只怕滋生短路的运动(如访问
Web 时),对
Web 财富的拜会有时过慢或推迟过高。若那种职务在一起进程中受阻,则全体应用程序必须等待响应完毕。 在使用异步的进度中,大家的应用程序可继续执行不正视Web
财富的别的工作,并会直接等候绿灯的义务顺遂完毕。

  那是局地优异的选择异步的采纳场景,以及部分在
.NET >= 4.5 后新增的类库。

亚洲必赢官网 1

  全数与用户界面相关的操作平时共享2个线程,所以利用异步对于利用 UI
线程的 App 来说是不行重庆大学的。

  即使说你的 App
全数操作都是一道的,也正是说,当1个线程出现堵塞,其它线程都会产出堵塞,更严重的是,
App 会结束响应。

亚洲必赢官网 2

 

  使用异步方法时,App
将继承响应
UI。如:最大和最小化,不过意义依然在后台执行(如:下载)。

 

并行编码方法

并行执行有多少个艺术,第①个是成立n个Task,一起运营。难题是怎么处理await点。各类task写八个await点是可怜的,因为遇到第三个await就立马回去,而不会打开全数职务并行执行。由此await不能够随便放。那么怎么着为一组Task设定await点呢?能够透过Task.WhenAll
这么些艺术,他会等待一组Task执行完成重回。

特定情景下,能够用Parallel.For
来开启一组任务,可是这些类并没有达成async形式,也正是它会堵塞当前线程,所以须求用多个Task来包裹它。

可知,非阻塞和互动不完全是一次事。

Task

.NET
4.0出产了新一代的八线程模型Task。async/await特性是与Task紧凑相关的,所以在打听async/await前务必足够通晓Task的应用。那里将以二个简短的德姆o来看一下Task的利用,同时与Thread的始建格局做一下对照。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Threading;
using System.Threading.Tasks;
 
namespace TestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("主线程启动");
 
            //.NET 4.5引入了Task.Run静态方法来启动一个线程
            Task.Run(() => { Thread.Sleep(1000); Console.WriteLine("Task1启动"); });
 
            //Task启动的是后台线程,假如要在主线程中等待后台线程执行完毕,可以调用Wait方法
            Task task = Task.Run(() => { Thread.Sleep(500); Console.WriteLine("Task2启动"); });
            task.Wait();
 
            Console.WriteLine("主线程结束");
        }
    }
}
 
Task的使用

率先,必须显明一点是Task运转的线程是后台线程,可是能够透过在Main方法中调用task.Wait()方法,使应用程序等待task执行实现。Task与Thread的叁个主要区分点是:Task底层是使用线程池的,而Thread每趟实例化都会创设二个新的线程。那里能够透过那段代码做二次注解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Threading;
using System.Threading.Tasks;
 
namespace TestApp
{
    class Program
    {
        static void DoRun1()
        {
            Console.WriteLine("Thread Id =" + Thread.CurrentThread.ManagedThreadId);
        }
 
        static void DoRun2()
        {
            Thread.Sleep(50);
            Console.WriteLine("Task调用Thread Id =" + Thread.CurrentThread.ManagedThreadId);
        }
 
        static void Main(string[] args)
        {
            for (int i = 0; i < 50; i++)
            {
                new Thread(DoRun1).Start();
            }
 
            for (int i = 0; i < 50; i++)
            {
                Task.Run(() => { DoRun2(); });
            }
 
            //让应用程序不立即退出
            Console.Read();
        }
    }
}
 
Task底层使用线程池

运作代码,能够观望DoRun1()方法每回的Thread
Id都以分裂的,而DoRun2()方法的Thread
Id是双重出现的。大家明白线程的创始和销毁是八个花费比较大的操作,Task.Run()每一回执行将不会即时成立叁个新线程,而是到CL奥迪Q5线程池查看是还是不是有空闲的线程,有的话就取一个线程处理这几个请求,处理完请求后再把线程放回线程池,那么些线程也不会应声撤回,而是设置为空闲状态,可供线程池再度调度,从而收缩支出。

② 、异步升高响应能力

  异步对也许引起短路的移动(例如应用程序访问
Web 时)至关心重视要。对
Web 能源的拜会有时非常的慢或会推迟。倘诺此类活动在一起进程中受阻,则整个应用程序必须等待。 在异步进程中,应用程序可继续执行不重视Web 能源的其余干活,直至潜在阻塞的任务到位。

  下图展现了异步编制程序升高响应能力的特出应用场景。包罗从
.NET Framework 4.5 和 Windows
运转时中列出的片段包蕴帮助异步编制程序的办法的类。

  由于具有与用户界面相关的移位一般共享1个线程,由此,异步对走访
UI 线程的应用程序来说特别重庆大学。 假若在1个体协会同应用程序中有其余的线程被打断了,那么全数线程都将被封堵,再严重一点,你的应用程序将会告一段落响应。

  使用异步方法时,应用程序将继承响应
UI。例如,你能够调整窗口的大小或最小化窗口;如若你不希望等待应用程序截至,则足以将其关闭。

 

叁 、更便于编写的异步方法

  C#
中的 async 和 await 关键字都是异步编制程序的大旨。通过行使那八个至关心注重要字,我们就能够在
.NET 轻松成立异步方法。

  示例:

 1         /// <summary>
 2         /// 异步访问 Web 
 3         /// </summary>
 4         /// <returns></returns>
 5         /// <remarks>
 6         /// 方法签名的 3 要素:
 7         ///     ① async 修饰符
 8         ///     ② 返回类型 Task 或 Task<TResult>:这里的 Task<int> 表示 return 语句返回 int 类型
 9         ///     ③ 方法名以 Async 结尾
10         /// </remarks>
11         async Task<int> AccessTheWebAsync()
12         {
13             //记得 using System.Net.Http 哦
14             var client = new HttpClient();
15 
16             //执行异步方法 GetStringAsync
17             Task<string> getStringTask = client.GetStringAsync("http://www.google.com.hk/");
18 
19             //假设在这里执行一些非异步的操作
20             Do();
21 
22             //等待操作挂起方法 AccessTheWebAsync
23             //直到 getStringTask 完成,AccessTheWebAsync 方法才会继续执行
24             //同时,控制将返回到 AccessTheWebAsync 方法的调用方
25             //直到 getStringTask 完成后,将在这里恢复控制。
26             //然后从 getStringTask 拿到字符串结果
27             string urlContents = await getStringTask;
28 
29             //返回字符串的长度(int 类型)
30             return urlContents.Length;
31         }

 

  若是 AccessTheWebAsync 在调用 GetStringAsync() 时没有此外操作(如:代码中的
Do()),你能够用这么的方法来简化代码。

string urlContents = await client.GetStringAsync("http://www.google.com.hk/");

  

  简单计算:

  (1)方法签名包罗一个 async 修饰符。

  (2)依照约定,异步方法的名称供给以“Async”后缀为尾声。

  (3)3
种回到类型:

    ① Task<TResult>:返回
TResult 类型。

    ②
Task:没有再次回到值,即重回值为 void。

    ③
void:只适用于异步事件处理程序。

  (4)方法一般包蕴至少多个await
表明式,该表达式标记1个点,大家可以改为悬挂点,在该点上,直到等待的异步操作完毕,之后的法子才能继续执行。
与此同时,该方法将挂起,并将控制权再次来到到点子的调用方。

  

  须求运用异步方法的话,我们平昔在系统内部使用所提供的重庆大学字
async 和 await 就足以了,剩余的任何事情,就留给编写翻译器吧。 

 

Task<TResult>

Task<TResult>是Task的泛型版本,那多少个之间的最大分化是Task<TResult>能够有多少个再次来到值,看一下代码应该一目理解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Threading;
using System.Threading.Tasks;
 
namespace TestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("主线程开始");
 
            Task<string> task = Task<string>.Run(() => { Thread.Sleep(1000); return Thread.CurrentThread.ManagedThreadId.ToString(); });
            Console.WriteLine(task.Result);
 
            Console.WriteLine("主线程结束");
        }
    }
}
 
Task<TResult>的使用

Task<TResult>的实例对象有3个Result属性,当在Main方法中调用task.Result的时候,将静观其变task执行完结并获得再次回到值,那里的功能跟调用task.Wait()是同样的,只是多了一个重回值。

三 、更便于编写的异步方法

  C#
中的 async 和 await 关键字都以异步编制程序的基本。通过应用这七个至关首要字,你能够利用
.NET framework 或 Windows
运营时中的能源轻松制造异步方法(差不离与创设同步方法同样轻松)。

  上面包车型客车演示演示了一种选拔async 和 await 定义的异步方法。

 1         /// <summary>
 2         /// 异步访问 Web 
 3         /// </summary>
 4         /// <returns></returns>
 5         /// <remarks>
 6         /// 方法签名的 3 要素:
 7         ///     ① async 修饰符
 8         ///     ② 返回类型 Task 或 Task<TResult>:这里的 Task<int> 表示 return 语句返回 int 类型
 9         ///     ③ 方法名以 Async 结尾
10         /// </remarks>
11         async Task<int> AccessTheWebAsync()
12         {
13             //记得 using System.Net.Http 哦
14             var client = new HttpClient();
15 
16             //执行异步方法 GetStringAsync
17             Task<string> getStringTask = client.GetStringAsync("http://www.google.com.hk/");
18 
19             //假设在这里执行一些非异步的操作
20             DoIndependentWork();
21 
22             //等待操作挂起方法 AccessTheWebAsync
23             //直到 getStringTask 完成,AccessTheWebAsync 方法才会继续执行
24             //同时,控制将返回到 AccessTheWebAsync 方法的调用方
25             //直到 getStringTask 完成后,将在这里恢复控制。
26             //然后从 getStringTask 拿到字符串结果
27             string urlContents = await getStringTask;
28 
29             //返回字符串的长度(int 类型)
30             return urlContents.Length;
31         }

 

  如若 AccessTheWebAsync 在调用 GetStringAsync
时没有别的操作,你能够用如此的不二法门来简化代码。

string urlContents = await client.GetStringAsync("http://www.google.com.hk/");

  

  依照上述代码进行简要总计:

  (1)方法签名蕴含二个 async 修饰符。

  (2)按照预约,异步方法的称谓以“Async”后缀为末段。

  (3)重回类型为下列项目之一:

    ① 假诺您的办法有操作数为
TResult 类型的回到语句,则为 Task<TResult>。

    ② 假若您的章程没有回到语句或持有没有操作数的回来语句,则为 Task。

    ③ 若是您编写的是异步事件处理程序,则为
void。

  (4)方法一般包蕴至少叁个await
表明式,该表达式标记2个点,在该点上,直到等待的异步操作完结章程才能继承。 同时,将艺术挂起,并且控制权将回到到格局的调用方。

  在异步方法中,可接纳提供的根本字和体系来提醒必要做到的操作,且编写翻译器会完结别的操作。 

 

肆 、异步方法的控制流(大旨)

  异步编制程序中最注重却不易懂的是控制流,即分化措施间的切换。以往,请用一颗感恩的心来考察下图。

亚洲必赢官网 3

  步骤解析:

  ① 事件处理程序调用并等候 AccessTheWebAsync() 异步方法。

  ② AccessTheWebAsync
创建 HttpClient 对象并调用它的 GetStringAsync 异步方法来下载网站内容。

  ③
假设 GetStringAsync 中生出了某种意况,这一场地挂起了它的历程。也许必须等待网站下载或部分其它阻塞的移动。为防止阻塞财富,GetStringAsync() 会将控制权出让给其调用方 AccessTheWebAsync。GetStringAsync 重回 Task,在那之中 TResult
为字符串,并且 AccessTheWebAsync 将职务分配给 getStringTask 变量。该职分表示调用 GetStringAsync 的正在拓展的长河,个中承诺当工作到位时产生实际字符串值。

  ④ 由于并未等待 getStringTask,因而,AccessTheWebAsync 能够继续执行不依赖于 GetStringAsync 得出最终结出的此外职分。该任务由对伙同方法 DoIndependentWork 的调用表示。

  ⑤ DoIndependentWork 是马到功成其工作并回到其调用方的一道方法。

  ⑥ AccessTheWebAsync 已成功工作,能够不受 getStringTask 的结果影响。 接下来,AccessTheWebAsync 需求计算并赶回该下载字符串的长短,但该格局仅在具备字符串时才能计算该值。因而,AccessTheWebAsync 使用2个 await
运算符来挂起其速度,并把控制权交给调用 AccessTheWebAsync 的方法。AccessTheWebAsync 将 Task<int> 重临至调用方。 该职务表示对爆发下载字符串长度的整数结果的2个答应。

  【备注】如若 GetStringAsync(即 getStringTask)在 AccessTheWebAsync 等待前形成,则控制权会保留在 AccessTheWebAsync 中。 借使异步调用进程(getStringTask) 已成功,并且 AccessTheWebSync
不必等待最后结出,则挂起接下来回来到 AccessTheWebAsync,但那会促成基金的浪费。

  在调用方内部(即使那是三个事件处理程序),处理情势将接二连三。在等候结果前,调用方可以开始展览不正视于 AccessTheWebAsync 结果的别的工作,不然就需静观其变片刻。事件处理程序等待 AccessTheWebAsync,而 AccessTheWebAsync 等待 GetStringAsync。

  ⑦ GetStringAsync 完结并生成贰个字符串结果。 字符串结果不是透过你预期的措施调用 GetStringAsync 所重临的。(请记住,此方法已在步骤 3
中回到八个职务。)相反,字符串结果存款和储蓄在象征完结章程 getStringTask 的天职业中学。 await
运算符从 getStringTask 中找寻结果。赋值语句将寻找到的结果赋给 urlContents。

  ⑧ 当 AccessTheWebAsync 具有字符串结果时,该办法能够测算字符串长度。然后,AccessTheWebAsync 工作也将完结,并且等待事件处理程序可三番五次行使。 

 

  你能够品味思考一下同台行为和异步行为之间的出入。当其工作成就时(第陆 步)会回到贰个体协会助实行方法,但当其工作挂起时(第 3 步和第 6
步),异步方法会重临三个职务值。在异步方法最后达成其工作时,职分会标记为已做到,而结果(假诺有)将积存在职分中。

 

async/await 特性

由此后边的陪衬,终于迎来了那篇文章的顶梁柱async/await,还是先经过代码来感受一下那三个本性的应用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Threading;
using System.Threading.Tasks;
 
namespace TestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("-------主线程启动-------");
            Task<int> task = GetLengthAsync();
            Console.WriteLine("Main方法做其他事情");
            Console.WriteLine("Task返回的值" + task.Result);
            Console.WriteLine("-------主线程结束-------");
        }
 
        static async Task<int> GetLengthAsync()
        {
            Console.WriteLine("GetLengthAsync Start"); 
            string str = await GetStringAsync();
            Console.WriteLine("GetLengthAsync End");
            return str.Length;
        }
 
        static Task<string> GetStringAsync()
        {
            return Task<string>.Run(() => { Thread.Sleep(2000); return "finished"; });
        }
    }
}
 
async/await 用法

先是来看一下async关键字。async用来修饰方法,申明那个方法是异步的,声明的法子的归来类型必须为:void或Task或Task<TResult>。重返类型为Task的异步方法中无需选用return重回值,而回到类型为Task<TResult>的异步方法中必须运用return再次来到1个TResult的值,如上述德姆o中的异步方法再次来到1个int。

再来看一下await关键字。await必须用来修饰Task或Task<TResult>,而且不得不出现在曾经用async关键字修饰的异步方法中。

一般状态下,async/await必须成对出现才有意义,借使2个主意评释为async,但却从不采纳await关键字,则那么些大意在实施的时候就被看作同步方法,那时编写翻译器也会抛出警示提醒async修饰的方法中并未动用await,将被用香港作家联谊会面举行方法运用。领悟了最主要字async\await的特点后,大家来看一下上述德姆o在支配台会输入什么吗。

亚洲必赢官网 4

输出的结果已经很强烈地报告大家整整实施流程了。GetLengthAsync异步方法刚最先是联合署名施行的,所以”GetLengthAsync
Start”字符串会被打字与印刷出来,直到遇见第3个await关键字,真正的异步职分GetStringAsync起首进行,await约等于起到三个标记/唤醒点的效果,同时将控制权放回给Main方法,”Main方法做任何事情”字符串会被打字与印刷出来。之后由于Main方法要求拜访到task.Result,所以就会等待异步方法GetLengthAsync的实施,而GetLengthAsync又等待GetStringAsync的实践,一旦GetStringAsync执行完结,就会回到await
GetStringAsync那几个点上实施往下实施,那时”GetLengthAsync
End”字符串就会被打印出来。

自然,大家也得以行使上面包车型地铁格局成功地点控制台的输出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Threading;
using System.Threading.Tasks;
 
namespace TestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("-------主线程启动-------");
            Task<int> task = GetLengthAsync();
            Console.WriteLine("Main方法做其他事情");
            Console.WriteLine("Task返回的值" + task.Result);
            Console.WriteLine("-------主线程结束-------");
        }
 
        static Task<int> GetLengthAsync()
        {
            Console.WriteLine("GetLengthAsync Start");
            Task<int> task = Task<int>.Run(() => { string str = GetStringAsync().Result;
                Console.WriteLine("GetLengthAsync End");
                return str.Length; });          
            return task;
        }
 
        static Task<string> GetStringAsync()
        {
            return Task<string>.Run(() => { Thread.Sleep(2000); return "finished"; });
        }
    }
}
 
不使用async\await

相对而言二种办法,是或不是async\await关键字的法则其实就是由此选拔三个线程完毕异步调用吗?答案是还是不是认的。async关键字标明能够在艺术内部选择await关键字,方法在推行到await前都以一道实施的,运转到await处就会挂起,并重返到Main方法中,直到await标记的Task执行达成,才提示回到await点上,继续向下实施。更深入点的牵线能够查看小说最后的参考文献。

四 、异步方法的控制流(大旨)

  异步编制程序中最需弄清的是控制流,即如何从一个办法移动到另三个主意,
请用一颗感恩的心来阅览下图。

  步骤解析:

  ① 事件处理程序调用并等候 AccessTheWebAsync 异步方法。

  ② AccessTheWebAsync
创制 HttpClient 对象并调用它的 GetStringAsync 异步方法来下载网站内容。

  ③
要是 GetStringAsync 中产生了某种意况,本场所挂起了它的历程。可能必须等待网站下载或局地任何阻塞的移位。为幸免阻塞能源,GetStringAsync 会将控制权出让给其调用方 AccessTheWebAsync。GetStringAsync 再次来到 Task,个中 TResult
为字符串,并且 AccessTheWebAsync 将职责分配给 getStringTask 变量。该义务表示调用 GetStringAsync 的正在展开的历程,个中承诺当工作完结时发生实际字符串值。

  ④ 由于并未等待 getStringTask,因而,AccessTheWebAsync 能够继续执行不借助于 GetStringAsync 得出最后结出的其余职责。该职务由对二头方法 DoIndependentWork 的调用表示。

  ⑤ DoIndependentWork 是马到成功其行事并回到其调用方的一块方法。

  ⑥ AccessTheWebAsync 已到位工作,能够不受 getStringTask 的结果影响。 接下来,AccessTheWebAsync 需求计算并赶回该下载字符串的长短,但该方法仅在具备字符串时才能猜度该值。因而,AccessTheWebAsync 使用叁个 await
运算符来挂起其速度,并把控制权交给调用 AccessTheWebAsync 的办法。AccessTheWebAsync 将 Task<int> 重返至调用方。 该职责表示对产生下载字符串长度的平头结果的叁个承诺。

  【备注】假若 GetStringAsync(即 getStringTask)在 AccessTheWebAsync 等待前形成,则控制权会保留在 AccessTheWebAsync 中。 假如异步调用进度(getStringTask) 已到位,并且 AccessTheWebSync
不必等待最终结果,则挂起接下来回到到 AccessTheWebAsync,但那会造成开支的浪费。

  在调用方内部(如若那是多个事件处理程序),处理情势将三番五次。在守候结果前,调用方能够展开不借助于于 AccessTheWebAsync 结果的其余干活,不然就需等候片刻。事件处理程序等待 AccessTheWebAsync,而 AccessTheWebAsync 等待 GetStringAsync。

  ⑦ GetStringAsync 完结并生成三个字符串结果。 字符串结果不是由此你预期的不二法门调用 GetStringAsync 所重临的。(请牢记,此办法已在步骤 3
中回到贰个职务。)相反,字符串结果存款和储蓄在象征完毕措施 getStringTask 的天职业中学。 await
运算符从 getStringTask 中寻找结果。赋值语句将追寻到的结果赋给 urlContents。

  ⑧ 当 AccessTheWebAsync 具有字符串结果时,该措施能够测算字符串长度。然后,AccessTheWebAsync 工作也将做到,并且等待事件处理程序可延续行使。 

 

  你能够尝试思考一下联合署名行为和异步行为之间的出入。当其行事做到时(第肆 步)会再次回到1个联机方法,但当其行事挂起时(第 3 步和第 6
步),异步方法会再次来到3个任务值。在异步方法最后形成其行事时,任务会标记为已做到,而结果(借使有)将积存在任务中。

 

伍 、异步中的线程

  异步方法目的在于成为非阻塞操作。异步方法中的
await 表明式在伺机的职务履行的同时不会阻塞当前线程。相反,await
表达式在继续执行时办法的其他部分并将控制权再次回到到异步方法的调用方。

  async 和 await
关键字不会导致成立其余线程。因为异步方法不会在其自己线程上运维,因此它不须要二十四线程。只有当方法处于活动状态时,该情势将在当下联合署名上下文中运转并运用线程上的岁月。能够运用 Task.Run 将占用大量CPU
的做事移到后台线程,不过后台线程不会赞助正在等候结果的历程变为可用状态。

  对于异步编制程序而言,该基于异步的艺术优于大致每一个用例中的现有措施。具体而言,此格局比 BackgroundWorker 更适用于
IO 绑定的操作,因为此代码更简约且无需提防超越争用规范。结合 Task.Run()
使用时,异步编制程序比 BackgroundWorker 更适用于 CPU
绑定的操作,因为异步编制程序将运转代码的协调细节与 Task.Run 传输至线程池的干活分别开来。

 

async/await 实际利用

微软一度对一部分基础类库的格局提供了异步达成,接下去将完结多个事例来介绍一下async/await的实在应用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Threading;
using System.Threading.Tasks;
using System.Net;
 
namespace TestApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("开始获取博客园首页字符数量");
            Task<int> task1 = CountCharsAsync("http://www.cnblogs.com");
            Console.WriteLine("开始获取百度首页字符数量");
            Task<int> task2 = CountCharsAsync("http://www.baidu.com");
 
            Console.WriteLine("Main方法中做其他事情");
 
            Console.WriteLine("博客园:" + task1.Result);
            Console.WriteLine("百度:" + task2.Result);
        }
 
        static async Task<int> CountCharsAsync(string url)
        {
            WebClient wc = new WebClient();
            string result = await wc.DownloadStringTaskAsync(new Uri(url));
            return result.Length;
        }
    }
}

五、线程

  异步方法目的在于成为非阻塞操作。异步方法中的
await 表达式在等候的职分正在周转时不会堵塞当前线程。相反,表明式在后续时登记格局的别的部分并将控制权再次来到到异步方法的调用方。

  async
和 await 关键字不会造成创立其余线程。因为异步方法不会在其本人线程上运维,因而它不须求三十二线程。只有当方法处于活动状态时,该措施将在此时此刻联合上下文中运作并选用线程上的年月。能够采纳 Task.Run 将占据大批量CPU
的行事移到后台线程,然则后台线程不会帮衬正在守候结果的进度变为可用状态。

  对于异步编制程序而言,该基于异步的措施优于差不离各样用例中的现有措施。具体而言,此方式比 BackgroundWorker 更适用于
IO 绑定的操作,因为此代码更简短且无需防备超越争用规范。结合 Task.Run 使用时,异步编制程序比 BackgroundWorker 更适用于
CPU 绑定的操作,因为异步编制程序将运转代码的和谐细节与 Task.Run 传输至线程池的工作分别开来。

 

六、async 和 await 修饰符

亚洲必赢官网,  当您利用 async 修饰符钦点该方法为异步方法时:

  • 能够应用 await 来钦命悬挂点。await
    运算符会告诉编译器,异步方法只有直到等待的异步进度执行到位,才能接二连三透过该点往下进行。同时,控制权将重临至异步方法的调用方。await
    表达式中异步方法在挂起后,假设该措施还尚无执行到位并脱离,finally 块中的将不会实施。

  • 标志的异步方法本人能够透过调用它的点子进行等待。异步方法中常见包含1个或三个await 运算符,当然,八个 await
    表明式都不存在也不会导致编写翻译器错误,可是编写翻译器会发生警示,该措施在履行的时候仍旧会遵循同步方法来执行,async
    其实只是1个标识的效应而已,告诉编写翻译器他“应该”是三个异步方法。

 

六、async 和 await

  倘诺由此使用 async 修饰符内定某种格局为异步方法,则会产出下边二种情状。

  • 标志的异步方法能够动用 await 来钦定悬挂点。await
    运算符通告编写翻译器异步方法唯有直到等待的异步进程达成才能接二连三通过该点。同时,控制权将重返至异步方法的调用方。

    await
    表明式中异步方法的挂起不能够使该方法退出,并且 finally 块不会运作。

  • 标志的异步方法本人能够通过调用它的措施等待。

  异步方法一般包含await 运算符的1个或三个匹配项,但缺少 await
表达式不会促成编写翻译器错误。假设异步方法未利用
await
运算符标记悬挂点,则该方式将用作共同方法执行,不管异步修饰符怎样。编写翻译器将为此类措施宣布二个警戒。

 

七 、重回类型和参数新闻

  在编写制定异步方法时,大家多方会动用
Task 和 Task<TResult> 作为再次回到类型。

 

  示例:

 1         static async Task<Guid> Method1Async()  //Task<Guid>
 2         {
 3             var result = Guid.NewGuid();
 4 
 5             await Task.Delay(1);
 6 
 7             //这里返回一个 Guid 的类型
 8             return result;
 9         }
10 
11         static async Task Method2Async()  //Task
12         {
13             //Do...
14 
15             await Task.Delay(1);
16 
17             //Do...
18 
19             //这里没有 return 语句
20         }

 1             //调用 Method1Async
 2             //方式一
 3             Task<Guid> t1 = Method1Async();
 4             Guid guid1 = t1.Result;
 5 
 6             //方式二
 7             Guid guid2 = await Method1Async();
 8 
 9             //调用 Method2Async
10             //方式一
11             Task t2 = Method2Async();
12             await t2;
13 
14             //方式二
15             await Method2Async();

  每一种再次回到的职务表示正在展开的办事。职分可包裹有关异步进度情况的新闻,借使未得逞,则最后会卷入来自进度的末段结出,或许是由该进度引发的老大。

 

  【疑问】那么
void 重临类型是在哪些处境下才使用的吗?

  首要用以异步的事件处理程序,异步事件处理程序平常作为异步程序的早先点。void
重回类型告诉了编写翻译器,无需对她开始展览等待,并且,对于 void
再次回到类型的不二法门,大家也无力回天对她进行相当的捕捉。

 

  异步方法无法在参数中扬言与运用
ref 和 out 关键字,但是异步方法能够调用包罗这个参数的法门。

 

柒 、再次来到类型和参数音信

  在
.NET 中,异步方法一般再次来到 Task 或 Task<TResult>。在异步方法中,await
运算符应用于通过调用另1个异步方法重回的职分。

  借使格局包涵 钦赐项目 TResult 的操作数的 return 语句,则将 Task<TResult> 钦点为回到类型。

  假如艺术不含任何
return 语句或带有不回去操作数的 return 语句,则将 Task 用作重回类型。

  上面包车型大巴言传身教演示怎样注脚并调用可回到 Task 或 Task<TResult>
的法门。

 1         static async Task<Guid> Method1Async()  //Task<Guid>
 2         {
 3             var result = Guid.NewGuid();
 4 
 5             await Task.Delay(1);
 6 
 7             //这里返回一个 Guid 的类型
 8             return result;
 9         }
10 
11         static async Task Method2Async()  //Task
12         {
13             //Do...
14 
15             await Task.Delay(1);
16 
17             //Do...
18 
19             //这里没有 return 语句
20         }

 1             //调用 Method1Async
 2             //方式一
 3             Task<Guid> t1 = Method1Async();
 4             Guid guid1 = t1.Result;
 5 
 6             //方式二
 7             Guid guid2 = await Method1Async();
 8 
 9             //调用 Method2Async
10             //方式一
11             Task t2 = Method2Async();
12             await t2;
13 
14             //方式二
15             await Method2Async();

  各样重回的天职表示正在进展的行事。职务可包裹有关异步进度境况的消息,假设未成功,则最后会卷入来自进度的终极结果或进程引发的不得了。

  异步方法还足以是有所 void 重回类型。该再次回到类型首要用来定义供给 void 重返类型的事件处理程序。异步事件处理程序平时作为异步程序的起初点。

  不能等待具有 void 重回类型的异步方法,并且一个void 重回值的调用方不能够捕获该措施引发的其它尤其。

  异步方法不恐怕表明C# 中的 ref 或 out 参数,但此方式能够调用具有此类参数的措施。

 

捌 、命名的约定

  依据约定,使用
async 的点子都应有以“Async”作为后缀,如:DownloadAsync() 。可是,假设某一约定中的事件、基类或接口有其余的样式约定,则足以忽略上述约定。例如,不应有修改或重命名常用事件处理程序,如 btnOpen_Click。

 

⑧ 、命名的约定

  根据约定,将“Async”追加到具有 async 修饰符的办法名称。

  借使某一约定中的事件、基类或接口协定建议任何名目,则足以忽略此预订。例如,你不应重命名常用事件处理程序,例如 btnOpen_Click。

 

传送门 

  1. 走进异步编制程序的社会风气 – 初步接触
    async/await(推荐)

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

  3. 走进异步编程的世界 –
    剖析异步方法(下)

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

 


【参考引用】微软官方文书档案图片

【参考】

 

传送门 

 


【参考引用】微软官方文书档案图片

 

 

] 利用 async await
的异步编制程序,.net利用async 利用 async await 的异步编制程序 【博主】反骨仔
【出处】 目录…

网站地图xml地图