Visual Studio Async CTP的实现原理浅析 - 跳出Task,构建自己的Awaiter
2011-04-01 15:26
627 查看
看完上篇之后,我们知道await关键字后面跟的是一个Task对象,虽然为了看起来很像一个实际方法,AsyncCTP类库为现有对象添加的扩展方法没有使用典型的Get/Make等字眼,更准确的说法应该是await后面应该跟的是一个Await对象,或者是一个有一个public类型的GetAwaiter()方法并且能返回Awaiter对象的对象,这里所谓的Awaiter对象和我们以往的说法稍微有些区别,因为是编译器层的语法糖,所以Awaiter对象并没有实际的意义,比如实现了一个IAwaitable之类的接口,它仅仅要求有一个BeginAwait和EndAwait方法。
看下面的代码片段:
我们希望能异步等待1000毫秒,编译器当然毫不客气的拒绝了我们的要求,因为从1000这个数字无法获得一个Awaiter(为了简洁,后面沿用这个说法,准确的说法应该是没有从中找到BeginAwait和EndAwait方法),为了达到我们的目的,我们利用Task给int添加一个GetAwaiter方法:
[code]{
[/code]
这样,await1000被编译器认同,我们的代码能顺利执行,但是我们还没有为Task指定执行我们需要的等待1000毫秒,所以await会马上返回。这里先不涉及Task的内容,我们使用另外一个方法,直接为Int类型实现BeginAwait和EndAwait两个方法,或者单独定义一个IntAwaiter类,上面的代码简单的修改为:
[code]{
[/code]
而IntAwaiter类的定义如下:
[code]{
[/code]
然后我们来写几句代码测试一下:
[code]await1000;
[/code]
结果如下:
IntAwaiter非常简单,实际上AsyncCTP中的TaskAwaiter也基本上就做了这些事,在BeginAwait中启动Task,在EndAwait中判断Task状态,如果成功完成,返回Task的Result对象,如果是Cancel或者Fault,则抛出异常。
有了前文和本文的了解,实际上如果一个应用中的异步方法是自己实现的而非像WCF一样由VS自动生成的代理类,那么完全可以在代码中处理async达到和await一样简洁的代码风格而不是让编译器来干这事,毕竟如果不是真的无法取代我不愿意带上130K的这家伙,而且Preview版无法调试await也很让人头疼。
看下面的代码片段:
await1000;
我们希望能异步等待1000毫秒,编译器当然毫不客气的拒绝了我们的要求,因为从1000这个数字无法获得一个Awaiter(为了简洁,后面沿用这个说法,准确的说法应该是没有从中找到BeginAwait和EndAwait方法),为了达到我们的目的,我们利用Task给int添加一个GetAwaiter方法:
publicstaticclassIntExtensions
[code]{
publicstaticTaskAwaiter<int>GetAwaiter(thisints)
{
TaskCompletionSource<int>tsc=newTaskCompletionSource<int>();
Task<int>task=tsc.Task;
tsc.TrySetResult(0);
returntask.GetAwaiter<0>();
}
}
[/code]
这样,await1000被编译器认同,我们的代码能顺利执行,但是我们还没有为Task指定执行我们需要的等待1000毫秒,所以await会马上返回。这里先不涉及Task的内容,我们使用另外一个方法,直接为Int类型实现BeginAwait和EndAwait两个方法,或者单独定义一个IntAwaiter类,上面的代码简单的修改为:
publicstaticIntAwaiterGetAwaiter(thisinti)
[code]{
returnnewIntAwaiter(i);
}
[/code]
而IntAwaiter类的定义如下:
publicclassIntAwaiter
[code]{
SynchronizationContext_UIContext=SynchronizationContext.Current;
int_Value=0;
publicIntAwaiter(inti)
{
_Value=i;
}
publicboolBeginAwait(Actioncontinuation)
{
if(SynchronizationContext.Current!=_UIContext)
{
returnfalse;
}
else
{
ThreadPool.QueueUserWorkItem((state)=>
{
Thread.Sleep(_Value);
_Value=5;
_UIContext.Send(newSendOrPostCallback((target)=>{continuation();}),null);
});
returntrue;
}
}
publicintEndAwait()
{
return_Value;
}
}
[/code]
然后我们来写几句代码测试一下:
listBox1.Items.Add(DateTime.Now);
[code]await1000;
listBox1.Items.Add(DateTime.Now);
await5000;
listBox1.Items.Add(DateTime.Now);
[/code]
结果如下:
IntAwaiter非常简单,实际上AsyncCTP中的TaskAwaiter也基本上就做了这些事,在BeginAwait中启动Task,在EndAwait中判断Task状态,如果成功完成,返回Task的Result对象,如果是Cancel或者Fault,则抛出异常。
有了前文和本文的了解,实际上如果一个应用中的异步方法是自己实现的而非像WCF一样由VS自动生成的代理类,那么完全可以在代码中处理async达到和await一样简洁的代码风格而不是让编译器来干这事,毕竟如果不是真的无法取代我不愿意带上130K的这家伙,而且Preview版无法调试await也很让人头疼。
相关文章推荐
- Visual Studio Async CTP的实现原理浅析 - 如何不使用async和await关键字来实现Async
- Netty构建分布式消息队列实现原理浅析
- Netty构建分布式消息队列实现原理浅析
- Netty构建分布式消息队列实现原理浅析(十六)
- ASP.NET 中 Session 实现原理浅析 [2] 状态管理器
- JIT动态编译器的原理与实现之实现自己CPU的程序(二)
- 自己模拟实现spring IOC原理
- 浅析 Linux 中的时间编程和实现原理,第 1 部分: Linux 应用层的时间编程
- 三十三天 大规模站点构建、lvs原理、lvs调度及nat模型实现、lvs dr模型及lxc虚拟化
- 回调函数原理及实现浅析
- 【java并发】基于JUC CAS原理,自己实现简单独占锁
- Java网络编程 - 浅析web服务器与浏览器的实现原理
- 数据库连接池原理 与实现(动脑学院Jack老师课后自己的练习有感)
- 转 ASP.NET 中 Session 实现原理浅析 [1] 会话的建立流程
- 深入FFM原理与实践(转载美团点评的文章,准备自己实现一遍FFM)
- 由自己的应用调用第三方视频应用的实现原理(笔记简述)
- ASP.NET 中 Session 实现原理浅析 [2] 状态管理器 (转)
- ASP.NET 中 Session 实现原理浅析 [1] 会话的建立流程
- 浅析redux-saga实现原理