posted at 2022.8.4 13:30 by Administrator
一、 何谓异步方法
应用程序启动时,操作系统会在内存中创建一个新的进程。进程是构成运行程序的资源的集合。在进程内部,系统创建一个称为线程的内核(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{ public class IncrementerEventArgs : EventArgs { public string Bless { get; set; } } public class Incrementer { public delegatevoid tvEventHandler<IncrementerEventArgs>(object source, IncrementerEventArgs e); public event tvEventHandler<IncrementerEventArgs> CountIceDisappear; public void 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); }} abstract class Observer { public int IceDisappearCount { get; set; } public Observer(Incrementer incrementer) { IceDisappearCount = 0; incrementer.CountIceDisappear += IncrementIceDisappearCount; } public abstract void IncrementIceDisappearCount(object source, IncrementerEventArgs e); } class WlanObserver : Observer { public WlanObserver(Incrementer incrementer) : base(incrementer) { } public override void IncrementIceDisappearCount(object source,IncrementerEventArgs e) { IceDisappearCount++; Console.WriteLine($"Hello,第{IceDisappearCount}次,{e.Bless} in {source}"); } } class WebObserver : Observer { public WebObserver(Incrementer incrementer) : base(incrementer){ } public override void 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; }} class Program { static void 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类,代码如下 :
class WebAsyncObserver : Observer { public WebAsyncObserver(Incrementer incrementer):base(incrementer) { } public override void IncrementIceDisappearCount(object source, IncrementerEventArgs e) { _ = CountWebAsync("http://www.china.cx/jing.aspx"); Console.WriteLine($"Hello,第{IceDisappearCount}次{e.Bless} in {source}"); IceDisappearCount++; } private async 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% !
9ea46509-e006-4972-b9ab-287329bb83f6|0|.0|96d5b379-7e1d-4dac-a6ba-1e50db561b04
Tags: app, C#, Web, 程序, 代码, 方法, 类, 模
IT技术