前言
新进阶的程序员可能对async、await用得比较多,却对之前的异步了解甚少。本人就是此类,因此打算回顾学习下异步的进化史。
本文主要是回顾async异步模式之前的异步,下篇文章再来重点分析async异步模式。
APM
APM 异步编程模型,Asynchronous Programming Model
早在C#1的时候就有了APM。虽然不是很熟悉,但是多少还是见过的。就是那些类是BeginXXX和EndXXX的方法,且BeginXXX返回值是IAsyncResult接口。
在正式写APM示例之前我们先给出一段同步代码:
//1、同步方法 private void button1_Click(object sender, EventArgs e) { Debug.WriteLine("【Debug】线程ID:" + Thread.CurrentThread.ManagedThreadId); var request = WebRequest.Create("https://github.com/");//为了更好的演示效果,我们使用网速比较慢的外网 request.GetResponse();//发送请求 Debug.WriteLine("【Debug】线程ID:" + Thread.CurrentThread.ManagedThreadId); label1.Text = "执行完毕!"; }
【说明】为了更好的演示异步效果,这里我们使用winform程序来做示例。(因为winform始终都需要UI线程渲染界面,如果被UI线程占用则会出现“假死”状态)
【效果图】
看图得知:
我们在执行方法的时候页面出现了“假死”,拖不动了。
我们看到打印结果,方法调用前和调用后线程ID都是9(也就是同一个线程)
下面我们再来演示对应的异步方法:(BeginGetResponse、EndGetResponse所谓的APM异步模型)
private void button2_Click(object sender, EventArgs e) { //1、APM 异步编程模型,Asynchronous Programming Model //C#1[基于IAsyncResult接口实现BeginXXX和EndXXX的方法] Debug.WriteLine("【Debug】主线程ID:" + Thread.CurrentThread.ManagedThreadId); var request = WebRequest.Cre<i>本文来源gaodai$ma#com搞$代*码网2</i>ate("https://github.com/"); request.BeginGetResponse(new AsyncCallback(t =>//执行完成后的回调 { var response = request.EndGetResponse(t); var stream = response.GetResponseStream();//获取返回数据流 using (StreamReader reader = new StreamReader(stream)) { StringBuilder sb = new StringBuilder(); while (!reader.EndOfStream) { var content = reader.ReadLine(); sb.Append(content); } Debug.WriteLine("【Debug】" + sb.ToString().Trim().Substring(0, 100) + "...");//只取返回内容的前100个字符 Debug.WriteLine("【Debug】异步线程ID:" + Thread.CurrentThread.ManagedThreadId); label1.Invoke((Action)(() => { label1.Text = "执行完毕!"; }));//这里跨线程访问UI需要做处理 } }), null); Debug.WriteLine("【Debug】主线程ID:" + Thread.CurrentThread.ManagedThreadId); }
【效果图】
看图得知:
- 启用异步方法并没有是UI界面卡死
- 异步方法启动了另外一个ID为12的线程
上面代码执行顺序:
前面我们说过,APM的BebinXXX必须返回IAsyncResult接口。那么接下来我们分析IAsyncResult接口: