posted at 2022.8.4 13:47 by 风信子
一、 何谓异步方法
应用程序启动时,操作系统会在内存中创建一个新的进程。进程是构成运行程序的资源的集合。在进程内部,系统创建一个称为线程的内核(kernel)对象,它代表了真正执行的程序,一旦进程建立,系统会在Main方法的第一行语句处开始线程的执行。
如果程序只使用一个线程,并且从第一条语句按顺序执行到最后一条,许多情况下,这种简单的模型会在性能、用户体验上导致运行缓慢等难以接受的行为。
C# 5.0 引入了一个用来构建异步方法的新特性----async/await。如果一个程序调用某个方法,并在等待方法执行所有处理后才继续执行,我们称这样的方法是同步的。相反,异步的方法在完成其所有工作之前就返回到调用方法。利用C#的async/await特性可以创建并使用异步方法。合理地使用异步方法可以大大减少线程的等待时间,优化服务器性能,提高客户良好体验。
C#的async/await特性一般由3个部分(调用方法(calling method)、异步(async)方法和await表达式)组成。
二、 何谓事件
我们知道,事件可以看作是设计模式中的发布/订阅者模式(或
称观察者模式)在.NET的一种实现方式,利用发布、订阅者模式可以建立一个事件大纲,由发布者建立事件,订阅者提供回调方法,形成一个完美的事件程序。事件也是委托的一种特殊形式,而委托则是对函数的封装,可以当作给方法的特征指定一个名称。当Dang发生有意义的事情时,事件对象处理通知过程。
三、 实现
下面我们来看一个使用异步方法优化事件的例子:
首先,我们建立一个Incrementer类作为发布者,它定义一个CountIceDisappear事件,即冰消计数事件。每次随机数是12的模或者小于12时将触发该事件。
其次,建立一个抽象类Observer作为订阅者,Observer类包括一个IceDisappearCount属性、 Observer(Incrementer incrementer)构造函数和一个IncrementIceDisappearCount抽象方法,Observer(Incrementer incrementer)的作用是订阅与初始化,IncrementIceDisappearCount的主要作用是构建通知订阅者界面,显示结果。
最后,主程序调用Incrementer类的DoCount方法。
假设目前有二个具体订阅者:Wlan Observer (使用局域网方式浏览的观察者)和Web Observer(使用互联网方式的观察者),那么,这个冰消计数事件的C#程序代码构建如下:
<supportedRuntimeversion="v4.0"sku=".NETFramework,Version=v4.7.2" />namespace ConsoleSD{ publicclassIncrementerEventArgs : EventArgs { publicstring Bless { get; set; } } publicclassIncrementer { publicdelegatevoidtvEventHandler<IncrementerEventArgs>(object source, IncrementerEventArgs e); publicevent tvEventHandler<IncrementerEventArgs> CountIceDisappear; publicvoid DoCount() { DateTime dt = DateTime.Now; IncrementerEventArgs args = new IncrementerEventArgs(); Random rnd = new Random(); int N=rnd.Next(100); for(int i = 1; i < (N+1); i++) { if (i%12==0&& CountIceDisappear != null) { args.Bless = "走,跑步去!"; CountIceDisappear(this,args); } } if (N<12 && CountIceDisappear != null) { args.Bless = "来,尝尝我做的清蒸鱼。"; CountIceDisappear(this, args); } Console.WriteLine("{0}", N); DateTime dt2 = DateTime.Now; TimeSpan timeSpan = dt2-dt; Console.WriteLine("耗时{0} ms",timeSpan.TotalMilliseconds); }} abstractclassObserver { publicint IceDisappearCount { get; set; } publicObserver(Incrementer incrementer) { IceDisappearCount = 0; incrementer.CountIceDisappear += IncrementIceDisappearCount; } publicabstractvoid IncrementIceDisappearCount(object source, IncrementerEventArgs e); } classWlanObserver : Observer { publicWlanObserver(Incrementer incrementer) : base(incrementer) { } publicoverridevoid IncrementIceDisappearCount(object source,IncrementerEventArgs e) { IceDisappearCount++; Console.WriteLine($"Hello,第{IceDisappearCount}次,{e.Bless} in {source}"); } } classWebObserver : Observer { publicWebObserver(Incrementer incrementer) : base(incrementer){ } publicoverridevoid IncrementIceDisappearCount(object source, IncrementerEventArgs e) { IceDisappearCount++; _ = CountWeb("http://www.china.cx/jing.aspx"); Console.WriteLine($"Hello,第{IceDisappearCount}次{e.Bless} in {source}"); } private int CountWeb(string site) { WebClient wc = new WebClient(); string result = wc.DownloadString(new Uri(site)); return result.Length; }} classProgram { staticvoid Main(string[] args) { Incrementer incrementer=new Incrementer(); WlanObserver wlanObserver=new WlanObserver(incrementer); incrementer.DoCount(); Incrementer incrementer1 = new Incrementer(); WebObserver webObserver=new WebObserver(incrementer1); incrementer1.DoCount(); } }}
效果图

这时我们发现,WebObserver订阅事件时间高达627ms,相当缓慢。经分析,原因是该订阅者要浏览订阅信息,需要先强qiang制zhi连接一个类似代理的jing.aspx页面,以下载上网许可,因此拖慢了传递信息速度。那么,如何有效地提高速度呢?这就要用到我们先前叙述的:采用Async异步方法。
我们增加一个WebAsyncObserver类,代码如下:
classWebAsyncObserver : Observer { publicWebAsyncObserver(Incrementer incrementer):base(incrementer) { } publicoverridevoid IncrementIceDisappearCount(object source, IncrementerEventArgs e) { _ = CountWebAsync("http://www.china.cx/jing.aspx"); Console.WriteLine($"Hello,第{IceDisappearCount}次{e.Bless} in {source}"); IceDisappearCount++; } privateasync Task<int> CountWebAsync(string site) { WebClient wc = new WebClient(); string result = await wc.DownloadStringTaskAsync(new Uri(site)); return result.Length; } } 主程序增加三行代码:
Incrementer incrementer2 = new Incrementer();
WebAsyncObserver webAsyncObserver = new WebAsyncObserver(incrementer2);
incrementer2.DoCount();
看一下效果:

使用Async异步方法大幅削减订阅时间,达到惊人的1-8.56/551≈98% !
b8a9c8f7-4bba-4750-9ca6-b3ba05878a6e|0|.0|96d5b379-7e1d-4dac-a6ba-1e50db561b04
Tags: app, C#, Web, 程序, 代码, 方法, 类, 模
IT技术