打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
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, nullnull);  
  52.   
  53.         }  
  54.   
  55.         private void DoWork1(int maxNumber, AsyncOperation asyncOp)  
  56.         {  
  57.             Exception e = null;  
  58.   
  59.             //判断该userState的任务仍在处理中  
  60.             if (!TaskCanceled(asyncOp.UserSuppliedState))  
  61.             {  
  62.                 try  
  63.                 {  
  64.                     int n = 0;  
  65.                     int percentage = 0;  
  66.                     while (n < maxNumber && !TaskCanceled(asyncOp.UserSuppliedState))  
  67.                     {  
  68.                         Thread.Sleep(100); //模拟耗时操作  
  69.                         percentage = (int)((float)n / (float)maxNumber * 100);  
  70.                         Work1ProgressChangedEventArgs progressChanageArgs =  
  71.                             new Work1ProgressChangedEventArgs(maxNumber, percentage, asyncOp.UserSuppliedState);  
  72.                         //任务1的进度通知  
  73.                         asyncOp.Post(new SendOrPostCallback(Work1ReportProgressCB), progressChanageArgs);   
  74.                         n++;  
  75.                     }  
  76.                 }  
  77.                 catch (Exception ex)  
  78.                 {  
  79.                     e = ex;  
  80.                 }  
  81.             }  
  82.   
  83.             this.Work1Complete(e, TaskCanceled(asyncOp.UserSuppliedState), asyncOp);  
  84.         }  
  85.   
  86.         private void Work1Complete(Exception exception, bool canceled, AsyncOperation asyncOp)  
  87.         {  
  88.             if (!canceled)  
  89.             {  
  90.                 lock (userStateToLifetime.SyncRoot)  
  91.                 {  
  92.                     userStateToLifetime.Remove(asyncOp.UserSuppliedState);  
  93.                 }  
  94.             }  
  95.   
  96.             Work1CompletedEventArgs e = new Work1CompletedEventArgs(exception, canceled, asyncOp.UserSuppliedState);  
  97.   
  98.             //通知指定的任务已经完成  
  99.             asyncOp.PostOperationCompleted(new SendOrPostCallback(Work1CompleteCB), e);  
  100.   
  101.             //调用 PostOperationCompleted 方法来结束异步操作的生存期。  
  102.             //为某个特定任务调用此方法后,再调用其相应的 AsyncOperation 对象会引发异常。  
  103.         }  
  104.   
  105.         private void Work1ReportProgressCB(object state)  
  106.         {  
  107.             Work1ProgressChangedEventArgs e = state as Work1ProgressChangedEventArgs;  
  108.   
  109.             OnWork1ProgressChanged(e);  
  110.         }  
  111.   
  112.         private void Work1CompleteCB(object state)  
  113.         {  
  114.             Work1CompletedEventArgs e = state as Work1CompletedEventArgs;  
  115.   
  116.             OnWork1Completed(e);  
  117.         }  
  118.  
  119.         #region Work1的进度通知和任务完成的事件  
  120.         public event Work1ProgressChangedEventHandler Work1ProgressChanged;  
  121.         protected virtual void OnWork1ProgressChanged(Work1ProgressChangedEventArgs e)  
  122.         {  
  123.             Work1ProgressChangedEventHandler temp = this.Work1ProgressChanged;  
  124.             if (temp != null)  
  125.             {  
  126.                 temp(this, e);  
  127.             }  
  128.         }  
  129.   
  130.         public event Work1CompletedEventHandler Work1Completed;  
  131.         protected virtual void OnWork1Completed(Work1CompletedEventArgs e)  
  132.         {  
  133.             Work1CompletedEventHandler temp = this.Work1Completed;  
  134.             if (temp != null)  
  135.             {  
  136.                 temp(this, e);  
  137.             }  
  138.         }   
  139.         #endregion   
  140.         #endregion  
  141.   
  142.         /// <summary>  
  143.         /// 取消指定userState的任务执行  
  144.         /// </summary>  
  145.         /// <param name="userState"></param>  
  146.         public void CancelAsync(object userState)  
  147.         {  
  148.             AsyncOperation asyncOp = userStateToLifetime[userState] as AsyncOperation;  
  149.             if (asyncOp != null)  
  150.             {  
  151.                 lock (userStateToLifetime.SyncRoot)  
  152.                 {  
  153.                     userStateToLifetime.Remove(userState);  
  154.                 }  
  155.             }  
  156.         }  
  157.   
  158.         /// <summary>  
  159.         /// 判断指定userState的任务是否已经被结束。返回值:true 已经结束; false 还没有结束  
  160.         /// </summary>  
  161.         /// <param name="userState"></param>  
  162.         /// <returns></returns>  
  163.         private bool TaskCanceled(object userState)  
  164.         {  
  165.             return (userStateToLifetime[userState] == null);  
  166.         }  
  167.   
  168.   
  169.     }  
  170.   
  171.     public class Work1ProgressChangedEventArgs :ProgressChangedEventArgs  
  172.     {  
  173.         private int totalWork = 1;  
  174.   
  175.         public Work1ProgressChangedEventArgs(int totalWork, int progressPercentage, object userState)  
  176.             : base(progressPercentage, userState)  
  177.         {  
  178.             this.totalWork = totalWork;  
  179.         }  
  180.   
  181.         /// <summary>  
  182.         /// Work1的总工作量  
  183.         /// </summary>  
  184.         public int TotalWork  
  185.         {  
  186.             get  
  187.             {  
  188.                 return totalWork;  
  189.             }  
  190.         }  
  191.     }  
  192.   
  193.     public class Work1CompletedEventArgs : AsyncCompletedEventArgs  
  194.     {  
  195.         public Work1CompletedEventArgs(Exception e, bool canceled, object state)  
  196.             : base(e, canceled, state)  
  197.         {  
  198.         }  
  199.   
  200.     }  
  201.   
  202. }  
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
WCF中UserState
【新提醒】【【AchorU3d学习笔记④ u3d 下载进度 u3d 圆形进度条 】异步加载场景及Loading进度条制作】
WCF技术剖析之十一:异步操作在WCF中的应用(上篇)
如何进行异步机带载调谐(静止调谐)
Socket 同步和异步模式
ext1中Ext.form.ComboBox默认值的设置
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服