简单实现C#异步 *** 作

简单实现C#异步 *** 作,第1张

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

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

一、框架结构

整个框架包括四个部分

1、基类抽象Opeartor
我把每个异步执行过程称为一个Operate,因此需要一个Opeartor去执行
2、FuncAsync
异步的Func
3、ActionAsync
异步的Action
4、Asynchorus
对ActionAsync和FuncAsync的封装

Operator
Operator是一个抽象类,实现了IOperationAsync和IContinueWithAsync两个接口。
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():获取返回值

1)、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,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为异步 *** 作打下了基础,接下来最重要的工作就是通过这两个类执行我们的异步 *** 作,为此我封装了一个异步 *** 作类
主要封装了以下几个部分:

WaitAll(IEnumerable<Operator> operations):等待所有 *** 作执行完毕 WaitAny(IEnumerable<Operator> operations):等待任意 *** 作执行完毕 ActionAsync FuncAsync ContinueWithAction 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,TParameter parameter){TParameter param = parameter;Operator operation = new FuncAsync<TParameter,param);operation.Invoke();return operation;}public static Operator Invoke<T1,T2,TResult>(Func<T1,T2 parameter2){Operator operation = new FuncAsync<T1,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,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,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,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,p=> P*2);Asynchrous.ContinueWithAsync(operators,Console.Writeline,"执行完成");}

每次执行完继续执行
可能有时候我们需要遍历一个集合,每个元素处理完成后我们需要输出XX处理完成

public voID Test{int[] parameters = {1,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,3
结束语

以上只是列出了部分重载方法,其他重载方法无非就是加参数,本质实际是一样的。

希望对大家的学习有所帮助,在这祝大家新年快乐,新的一年大家一起努力。

总结

以上是内存溢出为你收集整理的简单实现C#异步 *** 作全部内容,希望文章能够帮你解决简单实现C#异步 *** 作所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1260745.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-08
下一篇 2022-06-08

发表评论

登录后才能评论

评论列表(0条)

保存