用Async异步方法描绘事件

posted at 2022.8.4 06:41 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
{
    public class IncrementerEventArgs : EventArgs
    {     
        public string Bless { get; set; }
    }
    public class Incrementer
    {
        public delegate void 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,相当缓慢。经分析,原因是该订阅者要浏览订阅信息,需要先强qiangzhi连接一个类似代理的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/55198%

Tags: , , , , , , ,

IT技术

Add comment

  Country flag

biuquote
  • Comment
  • Preview
Loading