威尼斯人线上娱乐

的异步编制程序,常见的异步格局async

1 4月 , 2019  

此前探究过c#的async和await关键字,幕后干了什么样,不过不亮堂干什么找不到相关资料了。未来重新讨论1回,顺便记录下来,方便今后翻看。

原来的文章地址: 

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

应用 async & await 的异步编程

【博主】反骨仔    【出处】   

基础知识

async
关键字标注二个艺术,该方法重回值是三个Task、或然Task<TResult>、void、包罗GetAwaiter方法的类型。该措施1般包涵三个await表达式。该表达式标注二个点,将被有个别异步方法回跳到该点。并且,当前函数执行到该点,将随即回到控制权给调用方。

如上描述了async方法想干的业务,至于怎么完成,那里就不阅读了。

 

运用 async & await 的异步编制程序

【博主】反骨仔    【出处】   

目录

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

 

个人见解

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

比如说async
方法分n个职分去下载网页并开始展览拍卖:先await下载,然后立时回去调用方,之后的处理就由异步线程完结下载后调用。那时候调用方能够继续执行它的职分,不过,如若调用方马上就供给async的结果,那么应该就只可以等待,但是多数景观:他一时不须要以此结果,那么就能够并行处理那么些代码。

可知,并行性映以后await 上,要是await
点和末段的数量结果偏离越远,那么并行度就越高。倘使await的点更加多,相信也会改革并行性。

资料展现,async 和await
关键字并不会成立线程,那是很主要的有些。
她们只是创立了贰个回去点,提供给须要她的线程使用。那么线程终究是何人创制?注意await
表达式的构成,他须求一个Task,三个Task并不表示一定要开创线程,也能够是另2个async方法,可是层层包裹最中间的主意,很或然就是二个原生的Task,比如await
Task.Run(()=>Thread.Sleep(0));
,那几个确实产生线程的口舌,就会基于前面那多少个await点,各种回调。

从那点来看,async
方法,未必就是一个异步方法,他在语义上越发贴近“非阻塞”,
当境遇阻塞操作,立刻用await定点再次回到,至于其它更深一层的消除手段,它就不关注了。那是程序员须求关切的,程序员必要用真的的创始线程代码,来形成异步操作(当然这一步可由库程序员完结)。

留意async的多少个重回值类型,那意味了不相同的利用情状。若是是void,表明客户端不保护数据同步难题,它只要求线程的控制权立刻回去。能够用在ui
等场所,假如是Task,客户端也不爱戴数据,不过它愿意能够支配异步线程,这可能是对职务执行顺序有自然的须要。当然,最广大的是Task<TResult>。

综上,async和await并不是为了多任务而设计的,借使追求高产出,应该在async函数内部用Task好好安排1番。在应用async
和await的时候,只需求遵守非阻塞的笔触去编写代码就能够了,至于幕后怎么处理就付出真正的10二线程代码创造者吧。

共同编制程序与异步编制程序

平日意况下,我们写的C#代码就是一只的,运营在同3个线程中,从程序的第三行代码到终极一句代码顺序执行。而异步编制程序的中坚是应用10二线程,通过让分裂的线程执行不一的职务,完毕分化代码的互相运维。

目录

  • 异步编制程序的简介
  • 异步升高响应能力
  • 更易于编写的异步方法
  • 异步方法的控制流(大旨)
  • 线程
  • async 和 await
  • 回来类型和参数音讯
  • 取名的约定

 

1、异步编制程序的简介

  通过利用异步编制程序,你能够幸免品质瓶颈并进步你的应用程序的壹体化响应能力。

  从
VS 二零一三 伊始,新引入了四个简化的章程,称为异步编制程序。我们在 >= .NET
④.五 仲春 Windows 运行时中采纳异步,编写翻译器它会赞助了作者们下落了已经实行的高难度异步代码编写的办事,但逻辑结构却好像于1块代码。因而,大家仅必要展开一小部分编制程序的干活就能够取得异步编制程序的拥有优点。

 

示范代码

        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( );//这里代表最终数据

为了完毕惊人并行,应该用真的的二10二十四线程代码:

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

前台线程与后台线程

关于十贰线程,早在.NET二.0权且,基础类库中就提供了Thread实现。暗许情状下,实例化多少个Thread创制的是前台线程,只要有前台线程在运营,应用程序的进度就径直处在运维景况,以控制台应用程序为例,在Main方法中实例化多个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("这是后台线程调用");
        }
    }
}

的异步编制程序,常见的异步格局async。运维方面包车型客车代码,能够看来DoRun二方法的打印音信“那是后台线程调用”将不会被出示出来,因为应用程序执行完主线程和前台线程后,就自动退出了,全部的后台线程将被电动终止。这里后台线程设置了等候1.伍s,固然那个后台线程比前台线程或主线程提前实施完毕,对应的音讯“那是后台线程调用”将可以被成功打字与印刷出来。

一、异步编制程序的简介

威尼斯人线上娱乐,  通过动用异步编制程序,你能够幸免质量瓶颈并增强应用程序的总体响应能力。

  Visual
Studio 2011 引入了四个简化的格局,异步编制程序,在 .NET Framework 四.伍 和
Windows 运行时选用异步辅助。编写翻译器可实施开发人士曾开始展览的高难度工作,且应用程序保留了一个看似于联合代码的逻辑结构。由此,您仅须要开始展览一小部分工作就能够博得异步编制程序的兼具优点。

 

2、异步升高响应能力

  异步对或者滋生短路的移动(如访问
Web 时),对
Web 能源的访问有时过慢或推迟过高。若那种职务在协同进程中受阻,则全体应用程序必须等待响应完毕。 在采纳异步的历程中,大家的应用程序可继续执行不依赖Web
财富的别的工作,并会平素守候绿灯的天职顺遂达成。

  这是壹些卓越的行使异步的行使场景,以及一些在
.NET >= 四.5 后新增的类库。

威尼斯人线上娱乐 1

  全数与用户界面相关的操作平日共享二个线程,所以使用异步对于使用 UI
线程的 App 来说是那么些首要的。

  假如说你的 App
全体操作都以一头的,也等于说,当二个线程出现堵塞,别的线程都晤面世堵塞,更要紧的是,
App 会结束响应。

威尼斯人线上娱乐 2

 

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

 

并行编码方法

并行执行有多少个章程,第3个是成立n个Task,一起运转。难题是怎么处理await点。种种task写一个await点是不行的,因为遇到第二个await就立马回到,而不会打开全体义务并行执行。因而await无法随便放。那么怎样为一组Task设定await点呢?能够透过Task.WhenAll
这一个艺术,他会等待1组Task执行完成重回。

特定情景下,能够用Parallel.For
来打开一组任务,然而那么些类并未兑现async格局,也正是它会堵塞当前线程,所以须要用一个Task来包裹它。

看得出,非阻塞和互动不完全是贰回事。

Task

.NET
四.0生产了新一代的10二线程模型Task。async/await脾性是与Task紧凑相关的,所以在询问async/await前务必充裕掌握Task的利用。那里将以1个简短的德姆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每一趟实例化都会创建2个新的线程。那里能够由此这段代码做贰遍验证:

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底层使用线程池

运转代码,能够看出DoRun一()方法每便的Thread
Id都以例外的,而DoRun二()方法的Thread
Id是再一次出现的。大家通晓线程的创造和销毁是多个开支相比较大的操作,Task.Run()每一次执行将不会立时创造三个新线程,而是到CL宝马X叁线程池查看是或不是有空闲的线程,有的话就取一个线程处理这几个请求,处理完请求后再把线程放回线程池,那么些线程也不会立马收回,而是设置为空闲状态,可供线程池再次调度,从而减弱支出。

贰、异步提升响应能力

  异步对可能滋生短路的运动(例如应用程序访问
Web 时)至关心注重要。对
Web 财富的造访有时极慢或会延迟。要是此类活动在1齐进度中受阻,则全体应用程序必须等待。 在异步进度中,应用程序可继续执行不依赖Web 能源的其余工作,直至潜在阻塞的天职成功。

  下图彰显了异步编程提升响应能力的头名应用场景。包蕴从
.NET Framework 四.5 和 Windows
运维时中列出的壹对含有帮助异步编制程序的艺术的类。

  由于具有与用户界面相关的移动一般共享三个线程,因而,异步对走访
UI 线程的应用程序来说更是重大。 假使在2个联合实行应用程序中有任何的线程被卡住了,那么富有线程都将被堵塞,再严重一点,你的应用程序将会终止响应。

  使用异步方法时,应用程序将持续响应
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 修饰符。

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

  (3)三种回到类型:

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

    2Task:未有重回值,即重返值为 void。

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

  (四)方法一般包涵至少1个await
表达式,该表明式标记多个点,我们能够改为悬挂点,在该点上,直到等待的异步操作完结,之后的措施才能继续执行。
与此同时,该措施将挂起,并将控制权重临到情势的调用方。

  

  须求运用异步方法的话,大家平素在系统里头使用所提供的第三字
async 和 await 就足以了,剩余的任何事情,就留给编译器吧。 

 

Task<TResult>

Task<TResult>是Task的泛型版本,那五个里面的最大不一致是Task<TResult>能够有3个再次回到值,看一下代码应该一目精晓:

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>的实例对象有八个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/");

  

  根据以上代码举办简易总结:

  (一)方法签名包括贰个 async 修饰符。

  (二)根据预约,异步方法的名称以“Async”后缀为尾声。

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

    1 如果你的不二法门有操作数为
TResult 类型的回来语句,则为 Task<TResult>。

    贰 假设你的办法未有回到语句或有所未有操作数的归来语句,则为 Task。

    叁 尽管你编写的是异步事件处理程序,则为
void。

  (4)方法1般包罗至少1个await
表明式,该表明式标记3个点,在该点上,直到等待的异步操作实现措施展才能能一连。 同时,将艺术挂起,并且控制权将回到到格局的调用方。

  在异步方法中,可利用提供的重大字和花色来提示必要形成的操作,且编写翻译器会形成别的操作。 

 

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

  异步编制程序中最重大却不易懂的是控制流,即分裂方法间的切换。今后,请用1颗感恩的心来察看下图。

威尼斯人线上娱乐 3

  步骤解析:

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

  2 AccessTheWebAsync
创立 HttpClient 对象并调用它的 GetStringAsync 异步方法来下载网址内容。

  三即使 GetStringAsync 中爆发了某种情状,本场合挂起了它的历程。恐怕必须等待网址下载或部分别样阻塞的移位。为防止阻塞财富,GetStringAsync() 会将控制权出让给其调用方 AccessTheWebAsync。GetStringAsync 重回 Task,个中 TResult
为字符串,并且 AccessTheWebAsync 将任务分配给 getStringTask 变量。该职分表示调用 GetStringAsync 的正在拓展的长河,当中承诺当工作做到时爆发实际字符串值。

  四 由于并未有等待 getStringTask,由此,AccessTheWebAsync 能够继续执行不借助于 GetStringAsync 得出最后结果的别的职责。该职分由对一起方法 DoIndependentWork 的调用表示。

  伍 DoIndependentWork 是做到其行事并回到其调用方的1块儿方法。

  六 AccessTheWebAsync 已到位工作,能够不受 getStringTask 的结果影响。 接下来,AccessTheWebAsync 需求总括并赶回该下载字符串的长短,但该方法仅在颇具字符串时才能揣度该值。因而,AccessTheWebAsync 使用一个 await
运算符来挂起其速度,并把控制权交给调用 AccessTheWebAsync 的不2诀窍。AccessTheWebAsync 将 Task<int> 再次回到至调用方。 该职务表示对发生下载字符串长度的平头结果的2个答应。

  【备注】假诺 GetStringAsync(即 getStringTask)在 AccessTheWebAsync 等待前形成,则控制权会保留在 AccessTheWebAsync 中。 假使异步调用过程(getStringTask) 已形成,并且 AccessTheWebSync
不必等待最后结出,则挂起接下来回到到 AccessTheWebAsync,但那会导致资金财产的浪费。

  在调用方内部(如若那是1个事件处理程序),处理情势将延续。在等候结果前,调用方能够拓展不借助于于 AccessTheWebAsync 结果的其他工作,不然就需等候片刻。事件处理程序等待 AccessTheWebAsync,而 AccessTheWebAsync 等待 GetStringAsync。

  7 GetStringAsync 完结并生成1个字符串结果。 字符串结果不是通过你预期的诀要调用 GetStringAsync 所重返的。(请牢记,此措施已在步骤 3中回到二个职分。)相反,字符串结果存款和储蓄在象征达成章程 getStringTask 的职责中。 await
运算符从 getStringTask 中查找结果。赋值语句将追寻到的结果赋给 urlContents。

  8 当 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再次回到一个TResult的值,如上述德姆o中的异步方法再次回到叁个int。

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

平时情形下,async/await必须成对出现才有含义,即使3个办法表明为async,但却未有利用await关键字,则这几个点子在执行的时候就被看成同步方法,那时编写翻译器也会抛出警示提醒async修饰的方法中尚无行使await,将被用香港作家联谊会师方法应用。理解了至关心注重要字async\await的脾性后,大家来看一下上述Demo在控制台会输入什么啊。

威尼斯人线上娱乐 4

出口的结果早就很显然地报告大家任何实施流程了。GetLengthAsync异步方法刚先导是手拉手执行的,所以”GetLengthAsync
Start”字符串会被打字与印刷出来,直到碰着第1个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前都以1道实施的,运营到await处就会挂起,并再次来到到Main方法中,直到await标记的Task执行达成,才提醒回到await点上,继续向下实施。更深远点的牵线能够查看作品最终的参考文献。

肆、异步方法的控制流(核心)

  异步编程中最需弄清的是控制流,即怎么着从一个办法移动到另一个主意,
请用1颗感恩的心来观望下图。

  步骤解析:

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

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

  3假设 GetStringAsync 中产生了某种意况,该景况挂起了它的进度。恐怕必须等待网址下载或局地别的阻塞的位移。为制止阻塞资源,GetStringAsync 会将控制权出让给其调用方 AccessTheWebAsync。GetStringAsync 再次回到 Task,在那之中 TResult
为字符串,并且 AccessTheWebAsync 将职务分配给 getStringTask 变量。该职务表示调用 GetStringAsync 的正在开始展览的历程,个中承诺当工作成功时爆发实际字符串值。

  四 由于尚未等待 getStringTask,因此,AccessTheWebAsync 能够继续执行不依靠于 GetStringAsync 得出最后结出的别样任务。该职务由对伙同方法 DoIndependentWork 的调用表示。

  五 DoIndependentWork 是瓜熟蒂落其工作并回到其调用方的一起方法。

  六 AccessTheWebAsync 已成功工作,能够不受 getStringTask 的结果影响。 接下来,AccessTheWebAsync 必要总括并赶回该下载字符串的长短,但该方式仅在具备字符串时才能总计该值。由此,AccessTheWebAsync 使用3个 await
运算符来挂起其速度,并把控制权交给调用 AccessTheWebAsync 的秘籍。AccessTheWebAsync 将 Task<int> 再次回到至调用方。 该任务表示对产生下载字符串长度的整数结果的三个答应。

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

  在调用方内部(若是那是3个事件处理程序),处理方式将再三再四。在等候结果前,调用方能够展开不借助于 AccessTheWebAsync 结果的任何干活,不然就需等待片刻。事件处理程序等待 AccessTheWebAsync,而 AccessTheWebAsync 等待 GetStringAsync。

  七 GetStringAsync 完结并生成贰个字符串结果。 字符串结果不是由此你预期的点子调用 GetStringAsync 所重临的。(请牢记,此办法已在步骤 三中回到二个职分。)相反,字符串结果存款和储蓄在代表完结措施 getStringTask 的义务中。 await
运算符从 getStringTask 中寻觅结果。赋值语句将追寻到的结果赋给 urlContents。

  捌 当 AccessTheWebAsync 具有字符串结果时,该措施能够测算字符串长度。然后,AccessTheWebAsync 工作也将成功,并且等待事件处理程序可继承运用。 

 

  你能够尝试思考一出手拉手行为和异步行为之间的差距。当其工作形成时(第5 步)会回来叁个联机方法,但当其行事挂起时(第 ③ 步和第 六步),异步方法会重临一个职务值。在异步方法最后成功其行事时,职务会标记为已成功,而结果(尽管有)将积存在职务中。

 

5、异步中的线程

  异步方法目的在于成为非阻塞操作。异步方法中的
await 表明式在守候的任务执行的还要不会卡住当前线程。相反,await
表明式在继续执行时方法的其他部分并将控制权重临到异步方法的调用方。

  async 和 await
关键字不会招致成立其余线程。因为异步方法不会在其自身线程上运维,由此它不必要四线程。唯有当方法处于活动状态时,该方法将在如今四头上下文中运作并应用线程上的光阴。能够利用 Task.Run 将占据大批量CPU
的工作移到后台线程,不过后台线程不会帮衬正在等候结果的进程变为可用状态。

  对于异步编制程序而言,该基于异步的主意优于大致各种用例中的现有措施。具体而言,此办法比 BackgroundWorker 更适用于
IO 绑定的操作,因为此代码更简单且无需防患超过争用口径。结合 Task.Run()
使用时,异步编制程序比 BackgroundWorker 更适用于 CPU
绑定的操作,因为异步编制程序将运维代码的协调细节与 Task.Run 传输至线程池的劳作分别开来。

 

async/await 实际利用

微软曾经对有些基础类库的章程提供了异步达成,接下去将落实2个事例来介绍一下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 块中的将不会履行。

  • 标志的异步方法本身能够通过调用它的方法开展等待。异步方法中家常便饭包蕴三个或多个await 运算符,当然,二个 await
    表达式都不设有也不会造成编译器错误,但是编写翻译器会爆发警告,该方法在履行的时候照旧会根据同步方法来推行,async
    其实只是3个标识的成效而已,告诉编译器他“应该”是三个异步方法。

 

六、async 和 await

  如若通过选择 async 修饰符钦定某种方式为异步方法,则会油不过生上面两种情景。

  • 标志的异步方法能够行使 await 来钦定悬挂点。await
    运算符通告编写翻译器异步方法唯有直到等待的异步进度做到才能一连透过该点。同时,控制权将重返至异步方法的调用方。

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

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

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

 

7、再次回到类型和参数音讯

  在编排异步方法时,大家多方会采用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 关键字,不过异步方法可以调用包括那些参数的主意。

 

7、重回类型和参数新闻

  在
.NET 中,异步方法1般重返 Task 或 Task<TResult>。在异步方法中,await
运算符应用于通过调用另三个异步方法重返的职务。

  假诺措施包涵 钦赐项目 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 参数,但此办法能够调用具有此类参数的措施。

 

8、命名的预订

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

 

八、命名的预订

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

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

 

传送门 

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

  2. 走进异步编制程序的世界 –
    剖析异步方法(上)

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

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

 


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

【参考】

 

传送门 

 


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

 

 

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


相关文章

发表评论

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

网站地图xml地图