• C#中的异步调用及异步设计模式(三)——基于事件的异步模式


    四、基于事件的异步模式(设计层面)

    基于事件的C#异步编程模式是比IAsyncResult模式更高级的一种异步编程模式,也被用在更多的场合。该异步模式具有以下优点:

    ·                  “在后台”执行耗时任务(例如下载和数据库操作),但不会中断您的应用程序。

    ·                  同时执行多个操作,每个操作完成时都会接到通知(在通知中可以区分是完成了哪个操作)。

    ·                  等待资源变得可用,但不会停止(“挂起”)您的应用程序。

    ·                  使用熟悉的事件和委托模型与挂起的异步操作通信。

    对于相对简单的应用程序可以直接用 .Net 2.0 新增的 BackgroundWorker 组件来很方便的实现,对于更复杂的异步应用程序则需要自己实现一个符合基于事件的C#异步编程模式的类。在实现基于事件的异步模式的设计前,需要了解基于 事件的异步模式的实现原理是什么。基于事件的异步模式需要以下三个类型的帮助。

    AsyncOperation:提供了对异步操作的生存期进行跟踪的功能,包括操作进度通知和操作完成通知,并确保在正确的线程或上下文中调用客户端的事件处理程序。

    public void Post(SendOrPostCallback d,Object arg);

    public void PostOperationCompleted(SendOrPostCallback d,Object arg);

    通过在异步辅助代码中调用Post方法把进度和中间结果报告给用户,如果是取消异步任务或提示异步任务已完成,则通过调 用PostOperationCompleted方法结束异步操作的跟踪生命期。在PostOperationCompleted方法调用 后,AsyncOperation对象变得不再可用,再次访问将引发异常。在此有个问题:在该异步模式中,通过AsyncOperation的Post函数来通知进度的时候,是如何使SendOrPostCallback委托在UI线程上执行的?针对该问题下文有具体分析。

     

    AsyncOperationManager:为AsyncOperation对象的创建提供了便捷方式,通过CreateOperation方法可以创建多个AsyncOperation实例,实现对多个异步操作进行跟踪。

     

    WindowsFormsSynchronizationContext:该类继承自SynchronizationContext类型,提供 Windows 窗体应用程序模型的同步上下文。该类型是基于事件异步模式通信的核心。之所以说该类型是基于事件异步模式的通信核心,是因为该类型解决了“保证SendOrPostCallback委托在UI线程上执行”的问题。它是如何解决的?请看AsyncOperation类型的Post方法的实现:

    1. /// <summary>  
    2.    /// AsyncOperation类型的Post方法的实现  
    3.    /// </summary>  
    4. public void Post(SendOrPostCallback d, object arg)  
    5. {  
    6.     this.VerifyNotCompleted();  
    7.     this.VerifyDelegateNotNull(d);  
    8.     this.syncContext.Post(d, arg);  
    9. }  


     

    在AsyncOperation类型的Post方法中,直接调用了SynchronizationContext类型的Post方法,再看该Post方法的实现:

    1. /// <summary>  
    2.    /// WindowsFormsSynchronizationContext类型的Post方法的实现  
    3.    /// </summary>  
    4. public override void Post(SendOrPostCallback d, object state)  
    5. {  
    6.     if (this.controlToSendTo != null)  
    7.     {  
    8.         this.controlToSendTo.BeginInvoke(d, new object[] { state }); //此处保证了SendOrPostCallBack委托在UI线程上执行  
    9.   
    10.     }  
    11. }  


     

    有以上三个类型(AsyncOpertion,AsyncOperationManager和SynchronizationContext)作为基础,实现基于事件的异步模式的进度通知和完成通知就轻松多了。下面用一个基于事件的异步模型的例子来结束本文章。

      1. using System;  
      2. using System.Collections.Generic;  
      3. using System.Text;  
      4. using System.ComponentModel;  
      5. using System.Collections.Specialized;  
      6. using System.Threading;  
      7.   
      8. namespace test  
      9. {  
      10.     /// <summary>  
      11.     /// 任务1的进度通知代理  
      12.     /// </summary>  
      13.     /// <param name="sender"></param>  
      14.     /// <param name="e"></param>  
      15.     public delegate void Work1ProgressChangedEventHandler(object sender, Work1ProgressChangedEventArgs e);  
      16.     /// <summary>  
      17.     /// 任务1的进度通知参数  
      18.     /// </summary>  
      19.     /// <param name="sender"></param>  
      20.     /// <param name="e"></param>  
      21.     public delegate void Work1CompletedEventHandler(object sender, Work1CompletedEventArgs e);  
      22.   
      23.     public class BasedEventAsyncWorker  
      24.     {  
      25.         private delegate void WorkerEventHandler(int maxNumber, AsyncOperation asyncOp);  
      26.         private HybridDictionary userStateToLifetime = new HybridDictionary();  
      27.   
      28.         public BasedEventAsyncWorker()  
      29.         { }  
      30.  
      31.         #region DoWork1的基于事件的异步调用  
      32.         public void DoWork1Async(object userState, int maxNumber)  
      33.         {  
      34.             AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(userState);  
      35.   
      36.             //userStateToLifetime有可能会同时被多线程访问,在此需要lock进行同步处理  
      37.             lock (userStateToLifetime.SyncRoot)  
      38.             {  
      39.                 if (userStateToLifetime.Contains(userState))  
      40.                 {  
      41.                     throw new ArgumentException(  
      42.                         "userState parameter must be unique",  
      43.                         "userState");  
      44.                 }  
      45.   
      46.                 userStateToLifetime[userState] = asyncOp;  
      47.             }  
      48.   
      49.             //异步开始任务1  
      50.             WorkerEventHandler workerDelegate = new WorkerEventHandler(DoWork1);  
      51.             workerDelegate.BeginInvoke(maxNumber, asyncOp, null, null);  
      52.         }  
      53.   
      54.         private void DoWork1(int maxNumber, AsyncOperation asyncOp)  
      55.         {  
      56.             Exception e = null;  
      57.   
      58.             //判断该userState的任务仍在处理中  
      59.             if (!TaskCanceled(asyncOp.UserSuppliedState))  
      60.             {  
      61.                 try  
      62.                 {  
      63.                     int n = 0;  
      64.                     int percentage = 0;  
      65.                     while (n < maxNumber && !TaskCanceled(asyncOp.UserSuppliedState))  
      66.                     {  
      67.                         Thread.Sleep(100); //模拟耗时操作  
      68.                         percentage = (int)((float)n / (float)maxNumber * 100);  
      69.                         Work1ProgressChangedEventArgs progressChanageArgs =  
      70.                             new Work1ProgressChangedEventArgs(maxNumber, percentage, asyncOp.UserSuppliedState);  
      71.                         //任务1的进度通知  
      72.                         asyncOp.Post(new SendOrPostCallback(Work1ReportProgressCB), progressChanageArgs);   
      73.                         n++;  
      74.                     }  
      75.                 }  
      76.                 catch (Exception ex)  
      77.                 {  
      78.                     e = ex;  
      79.                 }  
      80.             }  
      81.   
      82.             this.Work1Complete(e, TaskCanceled(asyncOp.UserSuppliedState), asyncOp);  
      83.         }  
      84.   
      85.         private void Work1Complete(Exception exception, bool canceled, AsyncOperation asyncOp)  
      86.         {  
      87.             if (!canceled)  
      88.             {  
      89.                 lock (userStateToLifetime.SyncRoot)  
      90.                 {  
      91.                     userStateToLifetime.Remove(asyncOp.UserSuppliedState);  
      92.                 }  
      93.             }  
      94.   
      95.             Work1CompletedEventArgs e = new Work1CompletedEventArgs(exception, canceled, asyncOp.UserSuppliedState);  
      96.   
      97.             //通知指定的任务已经完成  
      98.             asyncOp.PostOperationCompleted(new SendOrPostCallback(Work1CompleteCB), e);  
      99.   
      100.             //调用 PostOperationCompleted 方法来结束异步操作的生存期。  
      101.             //为某个特定任务调用此方法后,再调用其相应的 AsyncOperation 对象会引发异常。  
      102.         }  
      103.   
      104.         private void Work1ReportProgressCB(object state)  
      105.         {  
      106.             Work1ProgressChangedEventArgs e = state as Work1ProgressChangedEventArgs;  
      107.   
      108.             OnWork1ProgressChanged(e);  
      109.         }  
      110.   
      111.         private void Work1CompleteCB(object state)  
      112.         {  
      113.             Work1CompletedEventArgs e = state as Work1CompletedEventArgs;  
      114.   
      115.             OnWork1Completed(e);  
      116.         }  
      117.  
      118.         #region Work1的进度通知和任务完成的事件  
      119.         public event Work1ProgressChangedEventHandler Work1ProgressChanged;  
      120.         protected virtual void OnWork1ProgressChanged(Work1ProgressChangedEventArgs e)  
      121.         {  
      122.             Work1ProgressChangedEventHandler temp = this.Work1ProgressChanged;  
      123.             if (temp != null)  
      124.             {  
      125.                 temp(this, e);  
      126.             }  
      127.         }  
      128.   
      129.         public event Work1CompletedEventHandler Work1Completed;  
      130.         protected virtual void OnWork1Completed(Work1CompletedEventArgs e)  
      131.         {  
      132.             Work1CompletedEventHandler temp = this.Work1Completed;  
      133.             if (temp != null)  
      134.             {  
      135.                 temp(this, e);  
      136.             }  
      137.         }   
      138.         #endregion   
      139.         #endregion  
      140.   
      141.         /// <summary>  
      142.         /// 取消指定userState的任务执行  
      143.         /// </summary>  
      144.         /// <param name="userState"></param>  
      145.         public void CancelAsync(object userState)  
      146.         {  
      147.             AsyncOperation asyncOp = userStateToLifetime[userState] as AsyncOperation;  
      148.             if (asyncOp != null)  
      149.             {  
      150.                 lock (userStateToLifetime.SyncRoot)  
      151.                 {  
      152.                     userStateToLifetime.Remove(userState);  
      153.                 }  
      154.             }  
      155.         }  
      156.   
      157.         /// <summary>  
      158.         /// 判断指定userState的任务是否已经被结束。返回值:true 已经结束; false 还没有结束  
      159.         /// </summary>  
      160.         /// <param name="userState"></param>  
      161.         /// <returns></returns>  
      162.         private bool TaskCanceled(object userState)  
      163.         {  
      164.             return (userStateToLifetime[userState] == null);  
      165.         }  
      166.   
      167.   
      168.     }  
      169.   
      170.     public class Work1ProgressChangedEventArgs :ProgressChangedEventArgs  
      171.     {  
      172.         private int totalWork = 1;  
      173.   
      174.         public Work1ProgressChangedEventArgs(int totalWork, int progressPercentage, object userState)  
      175.             : base(progressPercentage, userState)  
      176.         {  
      177.             this.totalWork = totalWork;  
      178.         }  
      179.   
      180.         /// <summary>  
      181.         /// Work1的总工作量  
      182.         /// </summary>  
      183.         public int TotalWork  
      184.         {  
      185.             get  
      186.             {  
      187.                 return totalWork;  
      188.             }  
      189.         }  
      190.     }  
      191.   
      192.     public class Work1CompletedEventArgs : AsyncCompletedEventArgs  
      193.     {  
      194.         public Work1CompletedEventArgs(Exception e, bool canceled, object state)  
      195.             : base(e, canceled, state)  
      196.         {  
      197.         }  
      198.   
      199.     }  
      200.   
  • 相关阅读:
    AppServ设置虚拟主机 及域名连接
    PHPCMS v9 实现首页,列表页,内容页调用点击量方法
    phpcms v9 后台首页 去掉团队信息等版权
    phpcms v9 在当前栏目下获取父栏目与当前栏目的名称与连接
    不是技术牛人,如何拿到国内IT巨头的Offer
    解决phpcms V9缩略图模糊的方法
    apache、nginx、iis 全球分布
    获取屏幕宽度、浏览器宽度、网页高度,宽度信息
    21个适合扁平化设计的创意超链接效果
    javascript模拟鼠标双击事件
  • 原文地址:https://www.cnblogs.com/zhaoxinshanwei/p/3878506.html
Copyright © 2020-2023  润新知