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方法的实现:

        /// <summary>
           /// AsyncOperation类型的Post方法的实现
           /// </summary>
        public void Post(SendOrPostCallback d, object arg)
        {
            this.VerifyNotCompleted();
            this.VerifyDelegateNotNull(d);
            this.syncContext.Post(d, arg);
        }


 

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

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

            }
        }


 

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

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Collections.Specialized;
using System.Threading;

namespace test
{
    /// <summary>
    /// 任务1的进度通知代理
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    public delegate void Work1ProgressChangedEventHandler(object sender, Work1ProgressChangedEventArgs e);
    /// <summary>
    /// 任务1的进度通知参数
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    public delegate void Work1CompletedEventHandler(object sender, Work1CompletedEventArgs e);

    public class BasedEventAsyncWorker
    {
        private delegate void WorkerEventHandler(int maxNumber, AsyncOperation asyncOp);
        private HybridDictionary userStateToLifetime = new HybridDictionary();

        public BasedEventAsyncWorker()
        { }

        #region DoWork1的基于事件的异步调用
        public void DoWork1Async(object userState, int maxNumber)
        {
            AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(userState);

            //userStateToLifetime有可能会同时被多线程访问,在此需要lock进行同步处理
            lock (userStateToLifetime.SyncRoot)
            {
                if (userStateToLifetime.Contains(userState))
                {
                    throw new ArgumentException(
                        "userState parameter must be unique",
                        "userState");
                }

                userStateToLifetime[userState] = asyncOp;
            }

            //异步开始任务1
            WorkerEventHandler workerDelegate = new WorkerEventHandler(DoWork1);
            workerDelegate.BeginInvoke(maxNumber, asyncOp, null, null);
        }

        private void DoWork1(int maxNumber, AsyncOperation asyncOp)
        {
            Exception e = null;

            //判断该userState的任务仍在处理中
            if (!TaskCanceled(asyncOp.UserSuppliedState))
            {
                try
                {
                    int n = 0;
                    int percentage = 0;
                    while (n < maxNumber && !TaskCanceled(asyncOp.UserSuppliedState))
                    {
                        Thread.Sleep(100); //模拟耗时操作
                        percentage = (int)((float)n / (float)maxNumber * 100);
                        Work1ProgressChangedEventArgs progressChanageArgs =
                            new Work1ProgressChangedEventArgs(maxNumber, percentage, asyncOp.UserSuppliedState);
                        //任务1的进度通知
                        asyncOp.Post(new SendOrPostCallback(Work1ReportProgressCB), progressChanageArgs); 
                        n++;
                    }
                }
                catch (Exception ex)
                {
                    e = ex;
                }
            }

            this.Work1Complete(e, TaskCanceled(asyncOp.UserSuppliedState), asyncOp);
        }

        private void Work1Complete(Exception exception, bool canceled, AsyncOperation asyncOp)
        {
            if (!canceled)
            {
                lock (userStateToLifetime.SyncRoot)
                {
                    userStateToLifetime.Remove(asyncOp.UserSuppliedState);
                }
            }

            Work1CompletedEventArgs e = new Work1CompletedEventArgs(exception, canceled, asyncOp.UserSuppliedState);

            //通知指定的任务已经完成
            asyncOp.PostOperationCompleted(new SendOrPostCallback(Work1CompleteCB), e);

            //调用 PostOperationCompleted 方法来结束异步操作的生存期。
            //为某个特定任务调用此方法后,再调用其相应的 AsyncOperation 对象会引发异常。
        }

        private void Work1ReportProgressCB(object state)
        {
            Work1ProgressChangedEventArgs e = state as Work1ProgressChangedEventArgs;

            OnWork1ProgressChanged(e);
        }

        private void Work1CompleteCB(object state)
        {
            Work1CompletedEventArgs e = state as Work1CompletedEventArgs;

            OnWork1Completed(e);
        }

        #region Work1的进度通知和任务完成的事件
        public event Work1ProgressChangedEventHandler Work1ProgressChanged;
        protected virtual void OnWork1ProgressChanged(Work1ProgressChangedEventArgs e)
        {
            Work1ProgressChangedEventHandler temp = this.Work1ProgressChanged;
            if (temp != null)
            {
                temp(this, e);
            }
        }

        public event Work1CompletedEventHandler Work1Completed;
        protected virtual void OnWork1Completed(Work1CompletedEventArgs e)
        {
            Work1CompletedEventHandler temp = this.Work1Completed;
            if (temp != null)
            {
                temp(this, e);
            }
        } 
        #endregion 
        #endregion

        /// <summary>
        /// 取消指定userState的任务执行
        /// </summary>
        /// <param name="userState"></param>
        public void CancelAsync(object userState)
        {
            AsyncOperation asyncOp = userStateToLifetime[userState] as AsyncOperation;
            if (asyncOp != null)
            {
                lock (userStateToLifetime.SyncRoot)
                {
                    userStateToLifetime.Remove(userState);
                }
            }
        }

        /// <summary>
        /// 判断指定userState的任务是否已经被结束。返回值:true 已经结束; false 还没有结束
        /// </summary>
        /// <param name="userState"></param>
        /// <returns></returns>
        private bool TaskCanceled(object userState)
        {
            return (userStateToLifetime[userState] == null);
        }


    }

    public class Work1ProgressChangedEventArgs :ProgressChangedEventArgs
    {
        private int totalWork = 1;

        public Work1ProgressChangedEventArgs(int totalWork, int progressPercentage, object userState)
            : base(progressPercentage, userState)
        {
            this.totalWork = totalWork;
        }

        /// <summary>
        /// Work1的总工作量
        /// </summary>
        public int TotalWork
        {
            get
            {
                return totalWork;
            }
        }
    }

    public class Work1CompletedEventArgs : AsyncCompletedEventArgs
    {
        public Work1CompletedEventArgs(Exception e, bool canceled, object state)
            : base(e, canceled, state)
        {
        }

    }

}


 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值