当前位置:编程学习 > wap >>

介绍一下.net 4.5中新的异步模式 async 和 await

为了简化异步编程,.net 4.5引入了两个新的关键字async和await,使得异步编程大大简化,代码可读性和可维护性成倍提高,不过代价总是有,就是程序员必须明白.net 4.0中引入的Task概念,没有Task基础知识,使用async和await会感觉一头雾水。就好像不明白delegate、generic而去强行使用LINQ一样。 

Task的出现是为了使多线程编程变得简单,Task和Thread还不是一回事,Task由TaskManager管理,一个Task会执行在一个Thread上,但是如果没有足够的Thread,TaskManager会暂时挂起这个Task,直到有足够的Thread资源为止。Task的另外一个好处是TaskManager会把执行这些Task的Thread自动的分配在不同的Core上,就是所谓的并行编程,拿我的i7来说,有4个物理Core。如果有4个Task,那么.net TaskManager会在4个Core上建立4个独立的Thread,然后把4个Task放到这4个Thread运行,有点像绕口令,这都是MSDN说的,我也不知道真假,也没测过,估计是真的吧

.net 4.0以后新出现的并行编程、异步编程框架都是基于Task,前段时间出现的Reactive Extention(Rx)也是如此。async和await和Rx有一些功能重复,Rx先按下不表,以后再说。

 用一个例子介绍一下async和await,这是前段时间我再给windows phone 8写app时的时候实际用到的。在没有async和await之前,类似的win phone代码简直乱得一团糟,写完了都不想再看第二眼(很好奇iPhone和安卓是怎样处理类似情况的?),现在写完了很想再看第二眼:

project: 根据email and password得到用户权限userRight,再根据userRight列出这个user能看到的所有电影movieList,

 先把代码放出,一个是同步,一个是async + await 异步

  static void Main(string[] args)
{
    Console.WriteLine("main thread started..");
    
    getUserMoves("me@hotmail.com", "password");
    getUserMoviesTaskAsync("me@hotmail.com","password");

    Console.WriteLine("waiting for main thread to end");
    Console.ReadLine();
}

private static void getUserMoves(string email, string password)
{
    WebClient wb = new WebClient();
    string userRight = wb.DownloadString(email + password);
    string moviesUserCanWatch = wb.DownloadString(userRight);
    Console.WriteLine(moviesUserCanWatch);
}

private static async void getUserMoviesTaskAsync(string email, string password)
{
    WebClient wb = new WebClient();
    string userRight = await wb.DownloadStringTaskAsync(email + password);
    string moviesUserCanWatch = await wb.DownloadStringTaskAsync(userRight);
    Console.WriteLine(moviesUserCanWatch);
}

第一个
  getUserMoves("me@hotmail.com", "password");
是同步代码,也就是说除非里面所有步骤都执行完毕,否则主线程会被block,你永远也看不到“waiting for main thread to end” 


第二个
  getUserMoviesTaskAsync("me@hotmail.com","password");
是异步代码,程序会输出:
main thread started..
 waiting for main thread to end
然后才会输出 downloaded string,主线程不会被block

写法极其相似,达到同样效果,但是一个是同步,一个是异步,异步的代码当然可以有其它多种实现方法,但是.net 4.5的这种async + await写法是最简洁的 大概讲一下原理:

 一旦一个函数被前面有async关键字,比如:
async void getUserMoviesTaskAsync
那么.net 在执行到这个函数的时候会像对待普通的函数一样去运行这个函数内的语句,同时主线程被block,等待getUserMoviesTaskAsync结束

 在执行 getUserMoviesTaskAsync 函数内的语句的时候,一旦遇到await关键字,比如:
await wb.DownloadStringTaskAsync(email + password);
 .net会建立另外的一个Thread去运行wb.DownloadStringTaskAsync(email + password)
同时把运行权交还给调用getUserMoviesTaskAsync函数的Object,在这里,就是Main(string[] args) {}啦,于是main继续运行输出:
“waiting for main thread to end”
当wb.DownloadStringTaskAsync(email + password)运行结束,.net会把运行权切换到getUserMoviesTaskAsync函数,让它继续运行,直到碰到下一个await,这时再次把运行权切换到主线程,然后再返回getUserMoviesTaskAsync函数,直到getUserMoviesTaskAsync函数运行结束,返回主线程 --------------------编程问答-------------------- 小弟以前的拙作一篇,发到这吧,初学者可能会有些帮助 --------------------编程问答-------------------- --------------------编程问答-------------------- 过来学习一下 --------------------编程问答-------------------- 求助啊 async + await 怎么在wp8中使用。。。 --------------------编程问答-------------------- 来    看看   说 什么 啊 --------------------编程问答-------------------- 其实用reflector看看vs把async和await编译成啥样就全明白了。。。感觉如果我之前不会用,看楼主的帖应该还是不会用- - --------------------编程问答-------------------- --------------------编程问答-------------------- 过来学习一下  --------------------编程问答-------------------- 这个await 和我们以前用的 Sleep(0)效果不一样吗? --------------------编程问答-------------------- 说到多核,如果asyn的函数可以分到其他核的话,是不是意味着asyn函数不能有副作用,也就是不能访问主线程的内存变量? --------------------编程问答-------------------- 学问低看不懂 --------------------编程问答-------------------- 我也想学学 真看不懂 --------------------编程问答-------------------- 非常简洁!

但是:
await wb.DownloadStringTaskAsync(email + password);


wb.DownloadStringTaskAsync 会在子线程中运行,对于该线程,是否可以通过程序去控制他? 比如中止操作。 --------------------编程问答-------------------- --------------------编程问答-------------------- 学习一下 --------------------编程问答-------------------- 这种异步其它语言里早就有了 --------------------编程问答-------------------- 官网的示例,更加直接! --------------------编程问答-------------------- 使用 Async 和 Await 的异步编程(C# 和 Visual Basic) --------------------编程问答-------------------- --------------------编程问答-------------------- 我正想学一下这种方式异步 async 和 await  --------------------编程问答-------------------- await wb.DownloadStringTaskAsync(email + password);
不加await就不会异步了吗?这个方法本来就是异步的吧?加await是为了等到它执行完毕,得到返回值之类的? --------------------编程问答-------------------- 路过帮顶。。。。。 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 楼主解释得很清楚,谢谢了。 --------------------编程问答-------------------- --------------------编程问答-------------------- ohyeyeyeyeyeye --------------------编程问答-------------------- 看不懂 --------------------编程问答-------------------- 除 --------------------编程问答--------------------
引用 13 楼 hyblusea 的回复:
非常简洁!

但是:
await wb.DownloadStringTaskAsync(email + password);


wb.DownloadStringTaskAsync 会在子线程中运行,对于该线程,是否可以通过程序去控制他? 比如中止操作。

当然可以了,怎么控制都行,暂停继续都可以,自己看MSDN。 --------------------编程问答-------------------- 其实很简单,标记了async的方法为异步方法,从方法的左大括号开始同步执行,直到第一个await出现就开始异步执行,主线程等待,等带await这行代码异步完了再回到主线程,然后继续往下执行。
如果后面又遇到带await语句的,又异步执行,执行完了就回来,继续同步往下。依此类推。
这样做其实就把我们以前编写等待句柄接收信号的代码给省掉了,就一个await就搞定。 --------------------编程问答-------------------- await确实方便很多 --------------------编程问答-------------------- 官网的示例,更加直接!  --------------------编程问答-------------------- 路过,学习一下 --------------------编程问答-------------------- 吓死人AAAAAA --------------------编程问答-------------------- 学习了 --------------------编程问答-------------------- 学习了学习了学习了 --------------------编程问答-------------------- --------------------编程问答-------------------- --------------------编程问答-------------------- 看看,以后肯定会使用到。。。 --------------------编程问答--------------------
引用 30 楼 tcjiaan 的回复:
其实很简单,标记了async的方法为异步方法,从方法的左大括号开始同步执行,直到第一个await出现就开始异步执行,主线程等待,等带await这行代码异步完了再回到主线程,然后继续往下执行。
如果后面又遇到带await语句的,又异步执行,执行完了就回来,继续同步往下。依此类推。
这样做其实就把我们以前编写等待句柄接收信号的代码给省掉了,就一个await就搞定。

学习了 --------------------编程问答-------------------- 除 --------------------编程问答-------------------- 海贼用 2.0 呢 --------------------编程问答-------------------- --------------------编程问答--------------------
引用 18 楼 mrlen 的回复:
使用 Async 和 Await 的异步编程(C# 和 Visual Basic)
好评 --------------------编程问答--------------------
引用 30 楼 tcjiaan 的回复:
其实很简单,标记了async的方法为异步方法,从方法的左大括号开始同步执行,直到第一个await出现就开始异步执行,主线程等待,等带await这行代码异步完了再回到主线程,然后继续往下执行。
如果后面又遇到带await语句的,又异步执行,执行完了就回来,继续同步往下。依此类推。
这样做其实就把我们以前编写等待句柄接收信号的代码给省掉了,就一个await就搞定。


这个说法有问题,异步执行时主线程并不处于等待状态,而是会继续向下执行,否则Main函数中的输出就不会再异步函数执行完之前出现了。
其实async和await只是一个语法糖而已,就像phommy说的看看编译结果就知道了。简单点说await相当于把下面未执行的代码包装成一个函数,作为异步函数返回的Task对象的ContinueWith的参数,同时帮着把结果传进去。
补充:移动开发 ,  Windows Phone
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,