前言

在.net4.0以后异步操作,并行计算变得异常简单,但是由于公司项目开发基于.net3.5所以无法用到4.0的并行计算以及Task等异步编程。因此,为了以后更方便的进行异步方式的开发,我封装实现了异步编程框架,通过BeginInvoke、EndInvoke的方式实现异步编程。

框架结构

整个框架包括四个部分

  1. 基类抽象Opeartor
    异步操作的基类,实现了异步操作接口
  2. FuncAsync
    异步的Func
  3. ActionAsync
    异步的Action
  4. Asynchorus
    对ActionAsync和FuncAsync的封装

    Operator

    Operator是一个抽象类,实现了IOperationAsyncIContinueWithAsync两个接口。
    IOperationAsync实现了异步操作,IContinueWithAsync实现了类似于Task的ContinueWith方法,在当前异步操作完成后继续进行的操作

    IOperationAsync接口详解

    public interface IOperationAsync{IAsyncResult Invoke();void Wait();void CompletedCallBack(IAsyncResult ar);void CatchException(Exception exception);}
  • Invoke():异步方法的调用
  • Wait():等待异步操作执行
  • CompletedCallBack():操作完成回调
  • CatchException():抓取异常

IContinueWithAsync接口详情

public interface IContinueWithAsync
{Operator Previous { get; set; }Operator Next { get; set; }Operator ContinueWithAsync(Action action);Operator ContinueWithAsync<TParameter>(Action<TParameter> action, TParameter parameter);
}
  • Previous:前一个操作
  • Next:下一个操作
  • ContinueWithAsync():异步继续操作
public abstract class Operator : IOperationAsync, IContinueWithAsync
{public IAsyncResult Middle;public readonly string Id;public Exception Exception { get; private set; }public Operator Previous { get; set; }public Operator Next { get; set; }protected Operator(){Id = Guid.NewGuid().ToString();}public abstract IAsyncResult Invoke();protected void SetAsyncResult(IAsyncResult result){this.Middle = result;}public virtual void Wait(){if (!Middle.IsCompleted) Middle.AsyncWaitHandle.WaitOne();}public virtual void CompletedCallBack(IAsyncResult ar){}public void CatchException(Exception exception){this.Exception = exception;}protected Operator ContinueAsync(){if (Next != null) Next.Invoke();return Next;}public virtual Operator ContinueWithAsync(Action action){Next = new ActionAsync(action);Next.Previous = this;return Next;}public virtual Operator ContinueWithAsync<TParameter>(Action<TParameter> action, TParameter parameter){Next = new ActionAsync<TParameter>(action, parameter);Next.Previous = this;return Next;}public virtual Operator ContinueWithAsync<TResult>(Func<TResult> func){Next = new FuncAsync<TResult>();Next.Previous = this;return Next;}public virtual Operator ContinueWithAsync<TParameter, TResult>(Func<TParameter, TResult> func,TParameter parameter){Next = new FuncAsync<TParameter, TResult>(func, parameter);Next.Previous = this;return Next;}
}

无返回异步操作

ActionAsync

public class ActionAsync : Operator
{private readonly Action _action;protected ActionAsync(){}public ActionAsync(Action action): this(){this._action = action;}public override IAsyncResult Invoke(){var middle = _action.BeginInvoke(CompletedCallBack, null);SetAsyncResult(middle);return middle;}public override void CompletedCallBack(IAsyncResult ar){try{_action.EndInvoke(ar);}catch (Exception exception){this.CatchException(exception);}ContinueAsync();}
}
public class ActionAsync<T> : ActionAsync
{public T Result;private readonly Action<T> _action1;protected readonly T Parameter1;public ActionAsync(){}public ActionAsync(T parameter){this.Parameter1 = parameter;}public ActionAsync(Action<T> action, T parameter){this._action1 = action;this.Parameter1 = parameter;}public override IAsyncResult Invoke(){var result = _action1.BeginInvoke(Parameter1, CompletedCallBack, null);SetAsyncResult(result);return result;}public override void CompletedCallBack(IAsyncResult ar){try{_action1.EndInvoke(ar);}catch (Exception exception){this.CatchException(exception);}ContinueAsync();}
}

有返回异步

FuncAsync实现了IFuncOperationAsync接口

IFuncOperationAsync

public interface IFuncOperationAsync<T>
{void SetResult(T result);T GetResult();
}
  • SetResult(T result):异步操作完成设置返回值
  • GetResult():获取返回值

    FuncAsync

public class FuncAsync<TResult> : Operator, IFuncOperationAsync<TResult>
{private TResult _result;public TResult Result{get{if (!Middle.IsCompleted || _result == null){_result = GetResult();}return _result;}}private readonly Func<TResult> _func1;public FuncAsync(){}public FuncAsync(Func<TResult> func){this._func1 = func;}public override IAsyncResult Invoke(){var result = _func1.BeginInvoke(CompletedCallBack, null);SetAsyncResult(result);return result;}public override void CompletedCallBack(IAsyncResult ar){try{var result = _func1.EndInvoke(ar);SetResult(result);}catch (Exception exception){this.CatchException(exception);SetResult(default(TResult));}ContinueAsync();}public virtual TResult GetResult(){Wait();return this._result;}public void SetResult(TResult result){_result = result;}
}
public class FuncAsync<T1, TResult> : FuncAsync<TResult>
{protected readonly T1 Parameter1;private readonly Func<T1, TResult> _func2;public FuncAsync(Func<T1, TResult> action, T1 parameter1): this(parameter1){this._func2 = action;}protected FuncAsync(T1 parameter1): base(){this.Parameter1 = parameter1;}public override IAsyncResult Invoke(){var result = _func2.BeginInvoke(Parameter1, CompletedCallBack, null);SetAsyncResult(result);return result;}public override void CompletedCallBack(IAsyncResult ar){try{var result = _func2.EndInvoke(ar);SetResult(result);}catch (Exception exception){CatchException(exception);SetResult(default(TResult));}ContinueAsync();}
}

Asynchronous 异步操作封装

ActionAsync和FuncAsync为异步操作打下了基础,接下来最重要的工作就是通过这两个类执行我们的异步操作,为此我封装了一个异步操作类
主要封装了以下几个部分:

  1. WaitAll(IEnumerable<Operator> operations):等待所有操作执行完毕
  2. WaitAny(IEnumerable<Operator> operations):等待任意操作执行完毕
  3. ActionAsync
  4. FuncAsync
  5. ContinueWithAction
  6. ContinueWithFunc

    后面四个包含若干个重载,这里只是笼统的代表一个类型的方法

    WaitAll

public static void WaitAll(IEnumerable<Operator> operations)
{foreach (var @operator in operations){@operator.Wait();}
}

WaitAny

public static void WaitAny(IEnumerable<Operator> operations)
{while (operations.All(o => !o.Middle.IsCompleted))Thread.Sleep(100);
}

等待时间可以自定义

ActionInvoke

public static Operator Invoke(Action action)
{Operator operation = new ActionAsync(action);operation.Invoke();return operation;
}
public static Operator Invoke<T>(Action<T> action, T parameter)
{Operator operation = new ActionAsync<T>(action, parameter);operation.Invoke();return operation;
}
public static Operator Invoke<T1, T2>(Action<T1, T2> action, T1 parameter1, T2 parameter2)
{Operator operation = new ActionAsync<T1, T2>(action, parameter1, parameter2);operation.Invoke();return operation;
}

FuncInvoke

public static Operator Invoke<TResult>(Func<TResult> func)
{Operator operation = new FuncAsync<TResult>(func);operation.Invoke();return operation;
}
public static Operator Invoke<TParameter, TResult>(Func<TParameter, TResult> func, TParameter parameter)
{TParameter param = parameter;Operator operation = new FuncAsync<TParameter, TResult>(func, param);operation.Invoke();return operation;
}
public static Operator Invoke<T1, T2, TResult>(Func<T1, T2, TResult> func, T1 parameter1, T2 parameter2)
{Operator operation = new FuncAsync<T1, T2, TResult>(func, parameter1, parameter2);operation.Invoke();return operation;
}

ContinueWithAction

public static Operator ContinueWithAsync(IEnumerable<Operator>operators, Action action)
{return Invoke(WaitAll, operators).ContinueWithAsync(action);
}
public static Operator ContinueWithAsync<TParameter>(IEnumerable<Operator> operators, Action<TParameter> action, TParameter parameter)
{return Invoke(WaitAll, operators).ContinueWithAsync(action, parameter);
}

ContinueWithFunc

public static Operator ContinueWithAsync<TResult>(IEnumerable<Operator> operators,Func<TResult> func)
{return Invoke(WaitAll, operators).ContinueWithAsync(func);
}
public static Operator ContinueWithAsync<TParameter, TResult>(IEnumerable<Operator> operators, Func<TParameter, TResult> func, TParameter parameter)
{return Invoke(WaitAll, operators).ContinueWithAsync(func, parameter);
}

这里有个bug当调用ContinueWithAsync后无法调用Wait等待,本来Wait需要从前往后等待每个异步操作,但是测试了下不符合预期结果。不过理论上来说应该无需这样操作,ContinueWithAsync只是为了当上一个异步操作执行完毕时继续执行的异步操作,若要等待,那不如两个操作放到一起,最后再等待依然可以实现。

前面的都是单步异步操作的调用,若需要对某集合进行某个方法的异步操作,可以foreach遍历

public void ForeachAsync(IEnumerbale<string> parameters)
{foreach(string p in parameters){Asynchronous.Invoke(Tast,p);}
}
public void Test(string parameter)
{//TODO:做一些事
}

每次都需要去手写foreach,比较麻烦,因此实现类似于PLinq的并行计算方法实在有必要,不过有一点差别,PLinq是采用多核CPU进行并行计算,而我封装的仅仅遍历集合进行异步操作而已

ForeachAction

public static IEnumerable<Operator> Foreach<TParameter>(IEnumerable<TParameter> items, Action<TParameter> action)
{return items.Select(t => Invoke(action, t)).ToList();
}

ForeachFunc

public static IEnumerable<Operator> Foreach<TParameter, TResult>(IEnumerable<TParameter> items, Func<TParameter, TResult> func)
{return items.Select(parameter => Invoke(func, parameter)).ToList();
}

如何使用

  • 无返回值异步方法调用
public void DoSomeThing()
{//TODO:
}

通过Asynchronous.Invoke(DoSomeThing) 执行

public void DoSomeThing(string parameter)
{//TODO:
}

通过Asynchronous.Invoke(DoSomeThing,parameter) 执行

  • 有返回值异步方法调用
public string DoSomeThing()
{//TODO:
}

通过Asynchronous.Invoke(()=>DoSomeThing())执行

public string DoSomeThing(string parameter)
{//TODO:
}

通过Asynchronous.Invoke(()=>DoSomeThing(parameter))执行,或者也可以传入参数通过Asynchronous.Invoke(p=>DoSomeThing(p),parameter)

  • 无返回值Foreach
public void Test
{int[] parameters = {1,2,3,4,5};Asynchronous.Foreach(parameters,Console.WriteLine);
}
  • 有返回值Foreach
public void Test
{int[] parameters = {1,2,3,4,5};var operators = Asynchronous.Foreach(parameters,p=> p*2);Asynchrous.WaitAll(operators);Asynchronous.Foreach(operators.Cast<FuncAsync<int,int>>(),p=> Console.WriteLine(p.Result));
}

首先将集合每个值扩大2倍,然后输出

  • 异步执行完再执行
public void Test
{int[] parameters = {1,2,3,4,5};var operators = Asynchronous.Foreach(parameters,p=> p*2);Asynchrous.ContinueWithAsync(operators,Console.WriteLine,"执行完成");
}
  • 每次执行完继续执行
    可能有时候我们需要遍历一个集合,每个元素处理完成后我们需要输出XX处理完成
public void Test
{int[] parameters = {1,2,3,4,5};var operators = Asynchronous.Foreach(parameters,p=> p*2);Asynchronous.Foreach(operators,o=>{o.ContinueWithAsync(()={//每个元素执行完时执行if(o.Exception != null){//之前执行时产生未处理的异常,这里可以捕获到  }});});
}
  • 可以实现链式异步操作
public void Chain()
{Asynchronous.Invoke(Console.WriteLine,1).ContinueWithAsync(Console.WriteLine,2).ContinueWithAsync(Console.WriteLine,3)
}

这样会按步骤输出1,2,3

结束语

以上只是列出了部分重载方法,其他重载方法无非就是加参数,本质实际是一样的,具体可以已提交至github。我还封装了for方法,但是感觉没什么用,而且也从没有用到过,这里不再提
通过以上的封装,已经能完成日常大部分的操作,调用还是比较方便的。

本文发布至作业部落

转载于:https://www.cnblogs.com/Jack-Blog/p/5182310.html

实现更简单的异步操作相关推荐

  1. 让CoreData更简单些

    从简书迁移到掘金 前言 本文并不是CoreData从入门到精通之类的教程, 并不会涉及到过多的原理概念描述, 而是介绍如何让CoreData的使用变得更加简单明了, 方便亲民. 全文约六千字, 预计花 ...

  2. PSS:更简单有效的End-to-End检测

    点击上方"视学算法",选择加"星标"或"置顶" 重磅干货,第一时间送达 作者丨SuperHui@知乎(已授权) 来源丨https://zhu ...

  3. 修改所有列_多人编辑,自动汇总,领导可见所有?用 SeaTable 表格更简单

    在日常办公中,经常会遇到这种情况,需要大家协作填写某个表格的数据,以便快速高效地汇总数据,同时为了保证填写人不能看到和修改别人的数据,就需要每个填写人只能看到自己所填写的数据,而表格数据收集人能看到所 ...

  4. 机器学习本该用起来更简单

    机器学习本该用起来更简单 作者 | Caleb Kaiser译者 | 王强免责声明:本文内容是基于我对一些机器学习团队的观察结果,而不是对这个行业的一份学术调查.利益相关,我需要先表明自己是 Cort ...

  5. 项目管理六大制约因素_知道了这7点,软件项目管理会变得更简单!

    软件项目管理,很多产品经理(项目经理)都在吐槽,自己怎么样难以管理,不好做.但是,软件项目管理虽然不易,但是也可以适当把软件项目管理变得更简单,更易于管理.但是需要多做一些管理工作.下面的七点,好好看 ...

  6. [转载]ICollectionView让MVVM更简单

    ICollectionView让MVVM更简单 (一)ICollectionView的作用 允许集合具有当前记录管理.自定义排序.筛选和分组这些功能. (二)如果在MVVM中不用ICollectonV ...

  7. 圆环,扇形控件基本算法一种实现 - 代码库 - CocoaChina_让移动开发更简单

    圆环,扇形控件基本算法一种实现 - 代码库 - CocoaChina_让移动开发更简单 // //  CircleCore.h //  Quartz // //  Created by 仙人掌 on ...

  8. 未来CPU内核将更简单!

    英特尔高级研究员:未来CPU内核将更简单!   2004/10/22 [日经BP社报道] 在英特尔公司负责系统架构研究部门的英特尔高级研究员.企业技术部门高级经理.系统技术实验室的贾斯廷·莱特纳(Ju ...

  9. python比java简单好学-python和java哪个学起来更简单

    在近几年Python的呼声越来越高,很多刚开始起步想要学习编程的朋友都会犹豫要不要选择学习Python,毕竟作为人工智能时代的首选语言这个诱惑还是很大的.在选择上最纠结的就是Python和Java选择 ...

  10. 云如何让App开发更简单?

    欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 互联网"下半场",移动App开发对于质量.速度的要求更加苛刻.4月初,腾讯云正式上线移动开发平台MobileLine,借 ...

最新文章

  1. 面向小白的最全 Python 可视化教程,超全的!
  2. python 坐标轴刻度_给妹子讲python-S02E08坐标轴与主次刻度
  3. 【数据结构与算法】之深入解析“恢复二叉搜索树”的求解思路与算法示例
  4. 从oracle里面取直,45个非常有用的 Oracle 查询语句小结
  5. 2018-2019-1 20189218《Linux内核原理与分析》第九周作业
  6. centos 7配置rsync源服务器
  7. master节点重置后添加node报错_超强教程!在树莓派上构建多节点K8S集群!
  8. 解读netty3.9的数据处理流程(一)
  9. web框架Django一
  10. 菜鸟学Linux 第048篇笔记 配置slave server
  11. java面试题框架篇
  12. JSONP解决前端跨域问题
  13. 市场上常见电阻阻值表
  14. y的花式写法_y的花式写法_26个字母的花式写法,总有一个你喜欢哒
  15. Code Composer Studio设置断点,并不能停在断点的解决办法
  16. Java入门学习笔记
  17. PLC通讯实现-C#实现AB5000 PLC串口通讯DTL32(七)
  18. Windows10总弹出打开文件安全警告怎么关闭
  19. 连接主机名失败但可以连接主机ip,能用ip地址连接却无法用主机名连接,看过来一站解决
  20. 20181217股市复盘

热门文章

  1. QQ自动登录 发消息给某人C++/C
  2. ENVI入门系列教程---一、数据预处理---3.2 遥感图像几何精校正
  3. Python3——通用序列操作
  4. 利用python gdal读写遥感影像
  5. PHP查询函数调用堆栈
  6. 计算机网络综合实践任务书,计算机网络综合实任务书2012-11.doc
  7. 每天一点正则表达式积累(三)
  8. OpenGL ES总结(三)OpenGL通过计算纹理坐标来显示一张图片
  9. thymeleaf随机数_JavaScript 产生不重复的随机数三种实现思路
  10. html5 图形水平运动,【分享】HTML5的Canvas制作3D动画效果分享