Async异步编程简介

Posted DotNet

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Async异步编程简介相关的知识,希望对你有一定的参考价值。


来源:坦荡

链接:http://www.cnblogs.com/tdws/p/5617242.html


从C#5.0异步编程Async和他将对你意味着什么来开始介绍吧!

 

异步编程


如果我们在一个耗时的操作中使用异步的代码,在其执行过程中,我们不需要无谓的等待。这种方式和在耗时操作的整个执行过程中的阻塞型代码是相对的。


我们所说的耗时操作包括:


·网络请求


·硬盘数据访问


·延迟一段时间的操作


全部的区别在于正在运行代码的线程。在广泛应用的编程语言当中,你的代码运行在操作系统的线程中。如果在遇到耗时操作时,你的线程可以继续去做其他事情,这就是异步编程。如果你的线程除了等待什么也不做,那就是同步的或者说是阻塞型代码。


当然我们还有第三种方式去处理耗时操作—轮询。这是一种不断重复“询问”耗时操作是否完成的操作。尽管它在处理段时间操作上有自己的地位,但这通常不是一个好的解决方案。

 

你也许在过去的工作中使用过异步编程。你可能开启一个新的线程或者使用线程池,这也是异步编程,因为你所工作的线程可以不被阻塞地去继续做其他事情。而你的console app,像Console.ReadLine(),这就是阻塞型,在web app中,如果也是这样的设计等待用户输入,将会是多么糟糕呀。


异步编程中很常见的难点在于这个操作在什么时候结束,以便于执行下一步的某些操作。但是这在阻塞型代码中,很容易做到:你只需要在将接下来的代码写在耗时操作的下一行就好。如果不加以处理,这种方式在异步的世界中是怎样也行不通的。因为几乎可以确定的是,你下一行代码是在耗时操作完成之前就已经执行了。


为了解决这个问题,我们发明了一些方式,为了在后台操作完成后去执行下一步操作:


·将下一步操作所需的代码插在耗时操作代码主体的后面


·注册一个当耗时操作结束时会触发的方法


·在完成后传递委托或者Lambad(回调)


如果你下一个操作需要在特定的线程上执行(例如Winform和WPF的UI线程),你还需要在这个线程上安排队列排序,这是很复杂的。

 

异步代码有什么了不起的?


异步编程释放了它开始的线程,这有许多原因确实不错。首先,线程占用并且占用很少的资源,通常只用一个线程就可以完成主要的工作,就像UI线程,但是如果你不尽快释放它,你的app就会出现未响应状态。



最重要的,也是最令我激动的一点是:异步编程让我们得以有机会去尽情享受计算机并行计算带来的好处。异步编程让我们以新的并且合理的方式构建应用程序,用更细粒度的并行和无需编写难以维护的复杂代码。第十章将会详细探讨此可能性。

 

什么是异步编程?


 在C#5.0当中,微软编译器团队为我们增加了一个强大的新功能。它以两个新型关键字出现:


·async


·await


它当然依赖于一些环境,要求你使用.NET FrameWork4.5,才能你的async代码有用。


Async是属于C#编译器的一个功能,不能被封装到一个类库,它对你的源代码进行改造,就像在早期C#版本对Lambda和迭代器所做的事情一样。

 

通过免去早期C#版本异步编程所需的复杂模式和代码,这个新功能使异步变得非常简单。有了这个功能,我们可以合理地用异步编程的风格编写整个项目。


异步编程一直在C#中是可行的的,它以前涉及编程者大量的手工工作,现在C#的async关键出现后,异步编程的使用变得非常容易。

 

异步编程Async做了什么?


Async功能提供了一种让你表达在耗时操作后需要做什么事情(执行什么代码)的方式,并且它易读易懂,表现为异步编程。


Async方法被编译器转化的像你平时所写的阻塞代码,这里有一段简单的下载网页的阻塞型代码:


private void DumpWebPage(string uri)

{

WebClient webClient = new WebClient();

string page = webClient.DownloadString(uri);

Console.WriteLine(page);

}


这里还有一段使用Async实现相同功能的代码:


private asyncvoid DumpWebPageAsync(string uri)

{

WebClient webClient = new WebClient();

string page = awaitwebClient.DownloadStringTaskAsync(uri);

Console.WriteLine(page);

}


两段代码在表面上看起来是非常相似的,但是在其外表下,有很大的不同。


被标记为Async的方法,要求方法使用await关键字,为了遵循惯例,我们也再方法的后缀名加上了Async。


有趣的地方是await关键字,当编译器遇到它时,他将方法分开(chop the method up),事实上它是很复杂的,所以现在我介绍一个我觉得更易于理解的简单情况的假结构。


1.await后所有的代码被分离到另一个方法。


2.我们使用一个新版本叫做DownloadStringTaskAsync的DownloadString方法,它做和原版相同的事情,但它是异步的。


3.这意味着我们可以给它新的第二种方法,即在它完成时它会调用。我们使用一些“魔法”来做这件事,稍后我会告诉你。


4.当下载结束,它将会把我们调用回来带着已经下载好的可以使用的string字符串,在这种情况下,写到控制台。


//这就是await分解的方法,上文所说的假的结构(译者博客园蜗牛注解)

private void DumpWebPageAsync(string uri)

{

WebClient webClient = new WebClient();

webClient.DownloadStringTaskAsync(uri)<- magic(SecondHalf);  //魔力的方法调回来

}

private void SecondHalf(string awaitedResult)

{

string page = awaitedResult;

Console.WriteLine(page);

}


当它运行此代码时,调用线程会发生什么?当线程抵达DownloadString

TaskAsync方法,下载工作开始,但并不在此线程中执行,在这个线程上,我们抵达了方法的结尾或者说是return,这个线程下一步做什么由我们调用者来决定。如果是UI线程,它将会返回执行用户操作,除此外,它的资源将会被释放,这意味着我们在做异步编程!

 

异步编程并不能解决所有问题


异步代码被微软编译器开发团队尽可能设计的像你常写的阻塞(同步)代码,我们可以把耗时操作或者远程操作处理地像本地操作和快速。但是保持和异步调用一样的性能和优势。


然而,这样的设计不是让你忘记Async是后台操作还有发生回调。你需要小心很多事情,包括:


·异常和try-catch-finally模块


·方法的返回值


·线程和上下文


·性能


如果不了解它真正发生了什么,你的应用程序可能会意想不到的挂掉,并且你将无法理解异常信息和没有能力去解决问题。

 

【今日微信公号推荐↓】




以上是关于Async异步编程简介的主要内容,如果未能解决你的问题,请参考以下文章

利用 async & await 的异步编程

.NET4.5新特性之异步编程(Async和Await)的使用

多线程之异步编程: 经典和最新的异步编程模型,async与await

温故知新,CSharp遇见异步编程(Async/Await),聊聊异步编程最佳做法

FlutterFuture 异步编程 ( 简介 | then 方法 | 异常捕获 | asyncawait 关键字 | whenComplete 方法 | timeout 方法 )

python异步(Async)编程