新进阶的程序员可能对async、await用得比较多,却对之前的异步了解甚少。本人就是此类,因此打算回顾学习下异步的进化史。
本文主要是回顾async异步模式之前的异步,下篇文章再来重点分析async异步模式。
APMAPM 异步编程模型,Asynchronous Programming Model
早在C#1的时候就有了APM。虽然不是很熟悉,但是多少还是见过的。就是那些类是BeginXXX和EndXXX的方法,且BeginXXX返回值是IAsyncResult接口。
在正式写APM示例之前我们先给出一段同步代码:
button1_Click(object sender, EventArgs e) { Debug.WriteLine(+ Thread.CurrentThread.ManagedThreadId); request.GetResponse();//发送请求 Debug.WriteLine(+ Thread.CurrentThread.ManagedThreadId); label1.Text = ; }
【说明】为了更好的演示异步效果,这里我们使用winform程序来做示例。(因为winform始终都需要UI线程渲染界面,如果被UI线程占用则会出现“假死”状态)
【效果图】
看图得知:
下面我们再来演示对应的异步方法:(BeginGetResponse、EndGetResponse所谓的APM异步模型)
private void button2_Click(object sender, EventArgs e) { //1、APM 异步编程模型,Asynchronous Programming Model //C#1[基于IAsyncResult接口实现BeginXXX和EndXXX的方法] Debug.WriteLine(+ Thread.CurrentThread.ManagedThreadId); ); request.BeginGetResponse(new AsyncCallback(t =>//执行完成后的回调 { var response = request.EndGetResponse(t); (StreamReader reader = new StreamReader(stream)) { StringBuilder sb = new StringBuilder(); while (!reader.EndOfStream) { var content = reader.ReadLine(); sb.Append(content); } Debug.WriteLine(+ sb.ToString().Trim().Substring();//只取返回内容的前100个字符 Debug.WriteLine(+ Thread.CurrentThread.ManagedThreadId); label1.Invoke((Action)(() => { label1.Text = ; }));//这里跨线程访问UI需要做处理 } }), null); Debug.WriteLine(+ Thread.CurrentThread.ManagedThreadId); }
【效果图】
看图得知:
上面代码执行顺序:
前面我们说过,APM的BebinXXX必须返回IAsyncResult接口。那么接下来我们分析IAsyncResult接口:
首先我们看:
确实返回的是IAsyncResult接口。那IAsyncResult到底长的什么样子?:
并没有想象中的那么复杂嘛。我们是否可以尝试这实现这个接口,然后显示自己的异步方法呢?
首先定一个类MyWebRequest,然后继承IAsyncResult:(下面是基本的伪代码实现)
public class MyWebRequest : IAsyncResult { public object AsyncState { get { throw new NotImplementedException(); } } public WaitHandle AsyncWaitHandle { get { throw new NotImplementedException(); } } public bool CompletedSynchronously { get { throw new NotImplementedException(); } } public bool IsCompleted { get { throw new NotImplementedException(); } } }
这样肯定是不能用的,起码也得有个存回调函数的属性吧,下面我们稍微改造下:
然后我们可以自定义APM异步模型了:(成对的Begin、End)
public IAsyncResult MyBeginXX(AsyncCallback callback) { var asyncResult = new MyWebRequest(callback, null); ); new Thread(() => //重新启用一个线程 { using (StreamReader sr = new StreamReader(request.GetResponse().GetResponseStream())) { var str = sr.ReadToEnd(); asyncResult.SetComplete(str);//设置异步结果 } }).Start(); return asyncResult;//返回一个IAsyncResult } public string MyEndXX(IAsyncResult asyncResult) { MyWebRequest result = asyncResult as MyWebRequest; return result.Result; }
调用如下: