先来看一个例子: async Task AsyncMethod(){Console.WriteLine( " Sync

时间:2021-12-29 02:28:53

异步编程的根本常识

C#5推出的async和await关键字使异步编程从外貌上来说变得简单了许多,我们只需要了解不久不多的常识就可以编写出有效的异步代码。

在介绍async和await之前,先介绍一些根本的观点:

并发:同时做很多工作。

这个解释直接表白了并发的感化。终端用户措施操作并发成果,在输入数据库的同时响应用户输入。处事器应用操作并发,在措置惩罚惩罚第一个请求的同时响应第二个请求。只要你但愿措施同时做多件工作,你就需要并发。几乎每个软件措施 城市受益于并发。

多线程:并发的一种形式,它给与多个线程来执行措施。

从字面上看,多线程就是使用多个线程。本书后续章节将介绍,多线程是并发的一种形式,但不是独一的形式。实际上,直接使用底层线程类型在现代措施中根基不起感化。 比起老式的多线程机制,给与高级的抽象机制会让措施成果越发强大、效率更高。因此,本书将尽量不涉及一些过时的技术。书中所有多线程的要领都给与高级类型,而不是Thread或BackgroundWorker。但是,不要认为多线程已经彻底被裁减了!因为线程池要求多线程继续存在。线程池存放任务的行列队伍,这个行列队伍能够按照需要自行调解。相应地,线程池孕育产生了另一个重要的并发形式:并行措置惩罚惩罚。

并行措置惩罚惩罚:把正在执行的大量的任务支解成小块,分配给多个同时运行的线程。

为了让措置惩罚惩罚器的操作效率最大化,并行措置惩罚惩罚(或并行编程)给与多线程。当现代多核CPU执行大量任务时,若只用一个核执行所有任务,而其他核连结空闲,这显然是不同理的。并行措置惩罚惩罚把任务支解成小块并分配给多个线程,让它们在差此外核上独立运行。并行措置惩罚惩罚是多线程的一种,而多线程是并发的一种。在现代措施中,还有一种非常重要但很多人还不熟悉的并发类型:异步编程。

异步编程:并发的一种形式,它给与future模式或回调(callback)机制,以制止孕育产生不须要的线程。

一个future(或promise)类型代表一些即将完成的操纵。在.NET中,新版future类型有Task和Task<TResult>。在老式异步编程API中,给与回调或事件(event),而不是future。异步编程的核心理念是异步操纵:启动了的操纵将会在一段时间后完成。这个操纵正在执行时,不会梗阻本来的线程。启动了这个操纵的线程,可以继续执行其他任务。当操纵完成时,会通知它的future,或者挪用回调函数,以便让措施知道操纵已经结束。异步编程是一种成果强大的并发形式,但直至不久前,实现异步编程仍需要出格庞大的代码。VS2012撑持async和await,这让异步编程变得几乎和同步(非并发)编程一样容易。

异步编程简介 异步编程的执行流程

现代的异步.NET措施使用两个关键字:async和await。async关键字加在要领声明上,它的主要目的是使要领内的await关键字生效(为了连结向后兼容,同时引入了这两个关键字)。如果async要领有返回值,应返回Task<T>;如果没有返回值,应返回Task。这些task类型相当于future,用来在异步要领结束时通知主措施。还有一种是返回void,这种就是存粹的为了兼容事件措置惩罚惩罚措施。所以,除了用于注册实践措置惩罚惩罚措施,不建议在另外处所使用返回void的异步代码。

先来看一个例子:

async Task AsyncMethod() { Console.WriteLine("Sync execute before await");//①同步执行的代码 await Task.Delay(TimeSpan.FromSeconds(5));//②异步期待,非梗阻 Console.WriteLine("callback method");//③任务的延续 }

和其他要领一样,async要领在开始时以同步方法执行①。在async要领内部,await关键字对它的参数执行一个异步期待②。它首先查抄操纵是否已经完成,如果完成了,就继续运行(同步方法)。否则,它会暂停async要领,并返回,留下一个未完成的task(token)。一段时间后,操纵完成,async要领就恢复运行③。就是这么简单。编译器在后面辅佐我们做了大量的事情。在后续的章节中,,会详细介绍编译器的所作所为。

同步上下文:一个async要领是由多个同步执行的措施块构成的,每个同步措施块之间由await语句分隔断绝分手②。第一个同步措施块在挪用这个要领的线程中运行,但其他同步措施块在哪里运行呢?情况对照庞大。最常见的情况是,用await语句期待一个任务完成,当该要领在await处暂停时,就可以捕捉上下文(context)。如果当前SynchronizationContext不为空,这个上下文就是当前SynchronizationContext。如果当前SynchronizationContext为空,则这个上下文为当前TaskScheduler。该要领会在这个上下文中继续运行③。一般来说,运行UI线程时给与UI上下文,措置惩罚惩罚ASP.NET请求时给与ASP.NET请求上下文,其他很多情况下则给与线程池上下文。因此,在上面的代码中,每个同步措施块会试图在原始的上下文中恢复运行。如果在UI线程中挪用DoSomethingAsync,这个要领的每个同步措施块都将在此UI线程上运行。但是,如果在线程池线程中挪用,每个同步措施块将在线程池线程上运行。要制止这种行为,可以在await中使用ConfigureAwait要领,将参数continueOnCapturedContext设为false。接下来的代码刚开始会在挪用的线程里运行,在被await暂停后,则会在线程池线程里继续运行。