目录1 使用异步编程的原因同步编程,服务器在响A服务的数据库读取,网页请求或者文件请求(这里我们统称为IO操作),如果延迟很大,此时如果来了B服务的IO请求,可能无法及时响应(阻塞),此时异步编程模式(非阻塞)应运而生。 异步编程模式是为了避免性能瓶颈并增强你的应用程序的总体响应能力。 2 异步编程模式2.1 APM模式APM(Asynchronous Programming Model) 是 net 1.0时期就提出的一种异步模式,并且基于IAsyncResult接口实现BeginXXX和EndXXX类似的方法. 2.1.1 APM模式示例代码class Program { static void Main(string[] args) { Console.WriteLine("===== 异步调用 AsyncInvokeTest ====="); WebResponseHandler handler = new WebResponseHandler(WebContentLength.GetResult); //IAsyncResult: 异步操作接口(interface) //BeginInvoke: 委托(delegate)的一个异步方法的开始 IAsyncResult result = handler.BeginInvoke( null, null); Console.WriteLine("继续做别的事情。"); //异步操作返回 Console.WriteLine(handler.EndInvoke(result)); Console.ReadKey(); } } public delegate string WebResponseHandler(); public class WebContentLength { public static string GetResult() { var client = new WebClient(); var content = client.DownloadString(new Uri("http://cnblogs.com")); return "网页字数统计:"+content.Length; } } 2.1.2 执行结果备注:APM又是建立在委托之上的。Net Core中的委托 不支持异步调用,也就是 BeginInvoke 和 EndInvoke 方法,即现代异步编程模型中,官方不推荐此模型。此例子使用 .Net FrameWork4.7框架。 2.1.3 APM回调例子当异步请求响应完成之后,会自动去调用回调方法,将网页字数统计结果打印。 class Program { static void Main(string[] args) { Console.WriteLine("===== 异步回调 AsyncInvokeTest ====="); WebResponseHandler handler = new WebResponseHandler(WebContentLength.GetResult); //异步操作接口(注意BeginInvoke方法的不同!) IAsyncResult result = handler.BeginInvoke( new AsyncCallback(CalllBack), "AsycState:OK"); Console.WriteLine("继续做别的事情。"); Console.ReadKey(); } static void CalllBack(IAsyncResult result) { WebResponseHandler handler = (WebResponseHandler)((AsyncResult)result).AsyncDelegate; Console.WriteLine(handler.EndInvoke(result)); Console.WriteLine(result.AsyncState); } } public delegate string WebResponseHandler(); public class WebContentLength { public static string GetResult() { var client = new WebClient(); var content = client.DownloadString(new Uri("http://cnblogs.com")); return "网页字数统计:" + content.Length; } } 备注:可以看出此种回调方式与人的思维逻辑相违背,当在回调函数中存在二级三级回调时,代码可读性变差,编程会变得比平常要困难一些。 2.1.4 执行结果2.2 EAP模式EAP(Event-based Asynchronous Pattern)基于事件的异步模式是 .net 2.0提出的,EAP异步编程算是C#对APM的一种补充,让异步编程拥有了一系列状态事件。实现了基于事件的异步模式的类将具有一个或者多个以Async为后缀的方法和对应的Completed事件,并且这些类都支持异步方法的取消、进度报告和报告结果。然而.net中并不是所有的类都支持EAP。 当我们使用EAP模式进行异步编程时,需要满足以下2个条件:
备注:当调用基于事件的EAP模式的类的XXXAsync方法时,就开始了一个异步操作,并且基于事件的EAP模式是基于APM模式之上的。EAP 是在 .NET Framework 2.0 版中引入的,在 winform,silverlight或者wpf变成中经常用到。 2.2.1 EAP模式编程示例1class Program { static void Main(string[] args) { WebClient wc = new WebClient(); wc.DownloadStringCompleted += Wc_DownloadStringCompleted; wc.DownloadStringAsync(new Uri("http://www.baidu.com")); Console.WriteLine("执行其他任务。"); Console.ReadKey(); } private static void Wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { Console.WriteLine("网页字数统计:" + e.Result.Length); } } 2.2.2 执行结果总结:此示例代码的编程模式有没有种似曾相识的感觉。没错,winform,wpf等的点击事件,网络库的接收方法中采用事件驱动型的异步编程模式。 2.2.3 封装一个EAP例子示例代码如下: /// <summary> /// EAP是对APM的封装 /// </summary> public class Worker { public enum WorkerStatus { Cancel = 0, Running = 1, Completed = 2 } public class WorkerEventArgs : EventArgs { public WorkerStatus Status { get; set; } public string Message { get; set; } } public Worker() { } public event EventHandler<WorkerEventArgs> OnWorkCompleted; IAsyncResult asyncResult = null; Thread thread = null; public void WorkAsync() { Worker _this = this; Action action = () => { thread = Thread.CurrentThread; Thread.Sleep(1000); Console.WriteLine(string.Format("线程:{0},Work Over.", Thread.CurrentThread.ManagedThreadId)); }; //result是IAsyncResult对象,此处无用 //当action委托完成调用之后,会调用如下回调方法。 asyncResult = action.BeginInvoke((result) => { WorkerEventArgs e = null; try { action.EndInvoke(result); } catch (ThreadAbortException ex) { e = new WorkerEventArgs() { Status = WorkerStatus.Cancel, Message = "异步操作被取消" }; } if (null != _this.OnWorkCompleted) { _this.OnWorkCompleted.Invoke(this, e); } },this); } public void CancelAsync() { if (null != thread) thread.Abort(); } } winform调用例子 异步嗲用WorkAsync,完成之后,事件异步调用WorkOver方法,并传入EventArgs参数。 public partial class Form1 : Form { public Form1() { InitializeComponent(); } Worker worker; private void btnStart_Click(object sender, EventArgs e) { worker = new Worker(); worker.OnWorkCompleted += WorkOver; worker.WorkAsync(); Console.WriteLine(string.Format("线程:{0}", Thread.CurrentThread.ManagedThreadId)); } private void btnCancel_Click(object sender, EventArgs e) { worker.CancelAsync(); } private void WorkOver(object sender, Worker.WorkerEventArgs e) { if (null != e) { if (Worker.WorkerStatus.Cancel == e.Status) { MessageBox.Show(e.Message); } } else { Console.WriteLine(string.Format("线程:{0},委托回调完成.", Thread.CurrentThread.ManagedThreadId)); } } } 2.2.4 执行结果
注意事项(重要):
3 代码仓库4 下篇预告: 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://www.cnblogs.com/JerryMouseLi/p/14100496.html |
|