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

cacaca6 2013-04-30 10:44:27
加精
为了简化异步编程,.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函数运行结束,返回主线程
...全文
10480 46 打赏 收藏 转发到动态 举报
写回复
用AI写文章
46 条回复
切换为时间正序
请发表友善的回复…
发表回复
fanfan_gg 2015-07-29
  • 打赏
  • 举报
回复
引用 30 楼 tcjiaan 的回复:
其实很简单,标记了async的方法为异步方法,从方法的左大括号开始同步执行,直到第一个await出现就开始异步执行,主线程等待,等带await这行代码异步完了再回到主线程,然后继续往下执行。 如果后面又遇到带await语句的,又异步执行,执行完了就回来,继续同步往下。依此类推。 这样做其实就把我们以前编写等待句柄接收信号的代码给省掉了,就一个await就搞定。
别误人子弟
北极猩猩 2013-10-19
  • 打赏
  • 举报
回复
引用 30 楼 tcjiaan 的回复:
其实很简单,标记了async的方法为异步方法,从方法的左大括号开始同步执行,直到第一个await出现就开始异步执行,主线程等待,等带await这行代码异步完了再回到主线程,然后继续往下执行。 如果后面又遇到带await语句的,又异步执行,执行完了就回来,继续同步往下。依此类推。 这样做其实就把我们以前编写等待句柄接收信号的代码给省掉了,就一个await就搞定。
这个说法有问题,异步执行时主线程并不处于等待状态,而是会继续向下执行,否则Main函数中的输出就不会再异步函数执行完之前出现了。 其实async和await只是一个语法糖而已,就像phommy说的看看编译结果就知道了。简单点说await相当于把下面未执行的代码包装成一个函数,作为异步函数返回的Task对象的ContinueWith的参数,同时帮着把结果传进去。
dahuatttt 2013-09-27
  • 打赏
  • 举报
回复
Truly 2013-09-27
  • 打赏
  • 举报
回复
猴头 2013-09-26
  • 打赏
  • 举报
回复
海贼用 2.0 呢
lhw7791086 2013-09-26
  • 打赏
  • 举报
回复
wang628962 2013-09-26
  • 打赏
  • 举报
回复
引用 30 楼 tcjiaan 的回复:
其实很简单,标记了async的方法为异步方法,从方法的左大括号开始同步执行,直到第一个await出现就开始异步执行,主线程等待,等带await这行代码异步完了再回到主线程,然后继续往下执行。 如果后面又遇到带await语句的,又异步执行,执行完了就回来,继续同步往下。依此类推。 这样做其实就把我们以前编写等待句柄接收信号的代码给省掉了,就一个await就搞定。
学习了
Delta 2013-09-26
  • 打赏
  • 举报
回复
看看,以后肯定会使用到。。。
su271521387 2013-09-25
  • 打赏
  • 举报
回复
masteng 2013-09-23
  • 打赏
  • 举报
回复
学习了
xusir98 2013-09-23
  • 打赏
  • 举报
回复
学习了学习了学习了
回文诗 2013-09-22
  • 打赏
  • 举报
回复
吓死人AAAAAA
wangrcaction 2013-09-22
  • 打赏
  • 举报
回复
路过,学习一下
鲈鱼6699 2013-09-22
  • 打赏
  • 举报
回复
官网的示例,更加直接!
xiaocongzhi 2013-09-21
  • 打赏
  • 举报
回复
await确实方便很多
东邪独孤 2013-09-21
  • 打赏
  • 举报
回复
其实很简单,标记了async的方法为异步方法,从方法的左大括号开始同步执行,直到第一个await出现就开始异步执行,主线程等待,等带await这行代码异步完了再回到主线程,然后继续往下执行。 如果后面又遇到带await语句的,又异步执行,执行完了就回来,继续同步往下。依此类推。 这样做其实就把我们以前编写等待句柄接收信号的代码给省掉了,就一个await就搞定。
东邪独孤 2013-09-21
  • 打赏
  • 举报
回复
引用 13 楼 hyblusea 的回复:
非常简洁! 但是:
await wb.DownloadStringTaskAsync(email + password);
wb.DownloadStringTaskAsync 会在子线程中运行,对于该线程,是否可以通过程序去控制他? 比如中止操作。
当然可以了,怎么控制都行,暂停继续都可以,自己看MSDN。
小晓说 2013-09-20
  • 打赏
  • 举报
回复
看不懂
nettman 2013-09-18
  • 打赏
  • 举报
回复
xiaoxiangqing 2013-09-18
  • 打赏
  • 举报
回复
楼主解释得很清楚,谢谢了。
加载更多回复(21)

7,655

社区成员

发帖
与我相关
我的任务
社区描述
Windows Phone是微软发布的一款手机操作系统,它将微软旗下的Xbox LIVE游戏、Zune音乐与独特的视频体验整合至手机中。
社区管理员
  • Windows客户端开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧