.NET 基于Task的异步编程模型
来源:互联网 发布:邮箱daum数据 编辑:程序博客网 时间:2024/05/16 03:42
最近下载了Visual Studio Async CTP,体验了下基于Task的异步编程带来的新特性。在CTP中,增加了新的关键字: async, await。尤其是在SL,WP7的编程中,大量使用异步调用的环境里,async, await的确能减少编程的复杂度。看上去像是同步的方法,其实编译器做了些手脚,悄悄的生成了回调的代码。比如:
- private async void button_Click(object sender, EventArgs e)
- {
- var client = new WebClient();
- var result = await client.DownloadStringTaskAsync("http://www.csdn.net");
- textBox1.Text = result;
- MessageBox.Show("Complete");
- }
(另外,注意:在button_Click的void之前加上了async关键字)
按照原来的写法:
- private void button3_Click(object sender, EventArgs e)
- {
- var client = new WebClient();
- client.DownloadStringCompleted += (s, evt) => {
- textBox1.Text = evt.Result;
- MessageBox.Show("Complete");
- };
- client.DownloadStringAsync(new Uri("http://www.csdn.net"));
- }
先回顾一下目前为止我们使用的异步编程方法:
1. 最简单的Thread:
- var thread = new Thread((obj) =>
- {
- // 模拟复杂的处理
- Thread.Sleep(1000);
- Console.WriteLine(obj);
- });
- thread.Start("some work");
2. Thread的包装演变出 APM (Asynchronous Programming Model):
最典型的代表:Delegate.BeginInvoke / EndInvoke。WCF的客户端代理类如果选择生成异步方法,那么也是BeginXXX,EndXXX这样的方法。
- Func<string, string> func = x =>
- {
- // 模拟复杂的处理
- Thread.Sleep(1000);
- return x + " is completed";
- };
- func.BeginInvoke("some work", ir =>
- {
- AsyncResult ar = (AsyncResult)ir;
- var delegateInstance = (Func<string, string>)ar.AsyncDelegate;
- var result = delegateInstance.EndInvoke(ir);
- Console.WriteLine(result);
- }, null);
3. 基于事件的APM——EAP(Event-based Asynchronous Pattern)
上面的BeginXXX,EndXXX的异步编程模型,在Callback上还是略显笨重,因此又演变出基于事件注册回调方法的模式。
最典型的代表就是 WebClient (HttpWebRequest 等)
- var client = new WebClient();
- client.DownloadStringCompleted += (s, evt) => {
- textBox1.Text = evt.Result;
- MessageBox.Show("Complete");
- };
- client.DownloadStringAsync(new Uri("http://www.csdn.net"));
4. 基于Task的APM——TAP(Task-based Asynchronous Pattern)
.net 4.0 里引入了并行编程库,Task成为新的异步编程主角,async, await 语法糖应运而生。为了实现async,await编译器将每个被async关键字标记的方法编译为一个方法所在类的一个内嵌类,所有在方法体内出现的变量会被转为这个类的字段,如果是一个实例方法,那么this所代表的对象也被声明为一个字段。这个类有两个核心成员:一个int来保存代码执行到哪一步的state,一个方法来执行真正的动作的 MoveNext() 方法。
比如下面的方法:
- static async void SimpleAsyncTest()
- {
- var client = new WebClient();
- var result1 = await client.DownloadStringTaskAsync("http://www.csdn.net");
- Console.WriteLine("complete");
- }
- private static void SimpleAsyncTest()
- {
- SimpleAsyncTestObj obj = new SimpleAsyncTestObj(0);
- obj.MoveNextDelegate = new Action(obj, (IntPtr)this.MoveNext);
- obj.builder = AsyncVoidMethodBuilder.Create();
- obj.MoveNext();
- }
SimpleAsyncTestObj:
- [CompilerGenerated]
- private sealed class SimpleAsyncTestObj
- {
- // Fields
- private bool disposing;
- public AsyncVoidMethodBuilder builder;
- private int state;
- public Action MoveNextDelegate;
- private TaskAwaiter<string> awaiter;
- public WebClient client;
- public string result;
- // Methods
- [DebuggerHidden]
- public SimpleAsyncTestObj(int state);
- [DebuggerHidden]
- public void Dispose();
- public void MoveNext();
- }
可以看到async方法被转化成类,然后调用了 MoveNext() ,初始的 state == 0,第一次调用如果没有 IsCompleted 则注册 awaiter 的 OnCompleted 事件,绑定的还是 MoveNext 方法。等awaiter 回调时,状态==1,直接进入 Label_0086 部分的代码,用 GetResult() 获取结果。
- public void MoveNext()
- {
- try
- {
- string str;
- bool flag = true;
- if (this.state != 1)
- {
- if (this.state != -1)
- {
- this.client = new WebClient();
- this.awaiter = this.client.DownloadStringTaskAsync("http://www.csdn.net").GetAwaiter<string>();
- if (this.awaiter.IsCompleted)
- {
- goto Label_0086;
- }
- this.state = 1;
- flag = false;
- this.awaiter.OnCompleted(this.MoveNextDelegate);
- }
- return;
- }
- this.state = 0;
- Label_0086:
- str = this.awaiter.GetResult();
- this.awaiter = new TaskAwaiter<string>();
- this.result = str;
- Console.WriteLine("over");
- }
- catch (Exception exception)
- {
- this.state = -1;
- this.builder.SetException(exception);
- return;
- }
- this.state = -1;
- this.builder.SetResult();
- }
如果方法中有多个 await 关键字的话,编译器生成的 MoveNext 则会是下面的样子:
public void MoveNext()
{
switch (state)
{
case 1:
...
state++;
// 注册第一个await对应异步的回调处理:回调中,获取结果,并调用下一个异步
break;
case 2:
...
state++;
// 注册第二个await对应异步的回调处理:回调中,获取结果,并调用下一个异步
break;
case 3:
....
state++;
break;
。。。
}
}
通过回调把下一个异步串起来,这么看来确实有 yield return 的感觉。看到这里相信大家都看出来在使用 TAP 编程时,最重要的是进行Task的设计,比如:
- static async void DoSomeWork(int i, string arg)
- {
- await new TaskFactory().StartNew(() =>
- {
- var random = new Random();
- // 模拟复杂的处理
- Thread.Sleep(i * 1000);
- Console.WriteLine(arg + " end");
- });
- }
- .NET 基于Task的异步编程模型
- .NET 基于Task的异步编程模型
- .Net 异步编程之Task
- 异步编程(2)——.NET的异步编程模型
- 异步编程(2)——.NET的异步编程模型
- Task异步编程
- C# Winform 基于Task的异步与延时执行
- 基于事件的异步编程
- 基于任务的异步编程
- 使用 Task 简化异步编程
- .net 4.5的异步编程
- 异步编程:基于事件的异步编程模式(EMP)
- 执行回调的异步编程模型
- 异步编程模型
- 基于消息的异步套接字编程
- 基于事件的异步编程模式
- 基于bind2f的异步编程框架
- C#异步编程之浅谈Task
- 新账号第一篇博文
- 简单例子
- 1 收集有趣的算法小程序
- OGRE
- DFS_FILE_SYSTEM bugcheck
- .NET 基于Task的异步编程模型
- 将输入中的制表符替换成适当数目的空格,使空格充满到下一个制表符终止位的地方
- What is a Perforce "shelved" file?
- 排序算法
- Http协议的几个概念和web browser优化
- hdu 1024 Max Sum Plus Plus(dp && 最大m子段和)
- 使用基于注解的AOP的事务管理 @Transaction (转)
- OgreSDK_vc9_v1-7-2下载地址与配置
- 标 题: 【原创】反NP监视原理(+Bypass NP in ring0)(转)