实现更简单的异步操作
2016-02-04 20:45
357 查看
前言
在.net4.0以后异步操作,并行计算变得异常简单,但是由于公司项目开发基于.net3.5所以无法用到4.0的并行计算以及Task等异步编程。因此,为了以后更方便的进行异步方式的开发,我封装实现了异步编程框架,通过BeginInvoke、EndInvoke的方式实现异步编程。框架结构
整个框架包括四个部分基类抽象Opeartor
异步操作的基类,实现了异步操作接口
FuncAsync
异步的Func
ActionAsync
异步的Action
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实现了IFuncOperationAsyncIFuncOperationAsyncpublic interface IFuncOperationAsync<T>
{
void SetResult(T result);
T GetResult();
}
SetResult(T result)
:异步操作完成设置返回值
GetResult()
:获取返回值
FuncAsyncpublic 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为异步操作打下了基础,接下来最重要的工作就是通过这两个类执行我们的异步操作,为此我封装了一个异步操作类
主要封装了以下几个部分:
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, 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方法,但是感觉没什么用,而且也从没有用到过,这里不再提
通过以上的封装,已经能完成日常大部分的操作,调用还是比较方便的。
本文发布至作业部落
相关文章推荐
- poj 1287 Networking
- python中yield语句详解——译自stack overflow
- 高精度整数 5
- Android学习路线(二十四)ActionBar Fragment运用最佳实践
- Quartz-Cron Expression 使用介绍
- MediaRecorder可以实现录音和录像
- CAS FOR WINDOW ACTIVE DIRECTORY SSO单点登录
- 数组
- ffmpeg安装
- 动态标绘演示系统1.0.1(for OpenLayers3)
- IPv4头部结构具体解释
- 【MongoDB】——可视化界面
- HDOJ 2073 无限的路
- HDOJ 2073 无限的路
- springmvc(十四)springmvc注解开发-springmvc参数绑定-数组绑定
- 单点登录系统cas资料汇总
- 解决 ORA-12514: TNS: 监听程序当前无法识别连接描述符中请求的服务
- How to configure CDB in Qt Creator(使用VC调试器)
- Java并发程序基础
- stringstream
public interface IFuncOperationAsync<T> { void SetResult(T result); T GetResult(); }
SetResult(T result):异步操作完成设置返回值
GetResult():获取返回值
FuncAsyncpublic 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为异步操作打下了基础,接下来最重要的工作就是通过这两个类执行我们的异步操作,为此我封装了一个异步操作类
主要封装了以下几个部分:
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, 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方法,但是感觉没什么用,而且也从没有用到过,这里不再提
通过以上的封装,已经能完成日常大部分的操作,调用还是比较方便的。
本文发布至作业部落
相关文章推荐
- poj 1287 Networking
- python中yield语句详解——译自stack overflow
- 高精度整数 5
- Android学习路线(二十四)ActionBar Fragment运用最佳实践
- Quartz-Cron Expression 使用介绍
- MediaRecorder可以实现录音和录像
- CAS FOR WINDOW ACTIVE DIRECTORY SSO单点登录
- 数组
- ffmpeg安装
- 动态标绘演示系统1.0.1(for OpenLayers3)
- IPv4头部结构具体解释
- 【MongoDB】——可视化界面
- HDOJ 2073 无限的路
- HDOJ 2073 无限的路
- springmvc(十四)springmvc注解开发-springmvc参数绑定-数组绑定
- 单点登录系统cas资料汇总
- 解决 ORA-12514: TNS: 监听程序当前无法识别连接描述符中请求的服务
- How to configure CDB in Qt Creator(使用VC调试器)
- Java并发程序基础
- stringstream
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为异步操作打下了基础,接下来最重要的工作就是通过这两个类执行我们的异步操作,为此我封装了一个异步操作类主要封装了以下几个部分:
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, 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方法,但是感觉没什么用,而且也从没有用到过,这里不再提
通过以上的封装,已经能完成日常大部分的操作,调用还是比较方便的。
本文发布至作业部落
相关文章推荐
- poj 1287 Networking
- python中yield语句详解——译自stack overflow
- 高精度整数 5
- Android学习路线(二十四)ActionBar Fragment运用最佳实践
- Quartz-Cron Expression 使用介绍
- MediaRecorder可以实现录音和录像
- CAS FOR WINDOW ACTIVE DIRECTORY SSO单点登录
- 数组
- ffmpeg安装
- 动态标绘演示系统1.0.1(for OpenLayers3)
- IPv4头部结构具体解释
- 【MongoDB】——可视化界面
- HDOJ 2073 无限的路
- HDOJ 2073 无限的路
- springmvc(十四)springmvc注解开发-springmvc参数绑定-数组绑定
- 单点登录系统cas资料汇总
- 解决 ORA-12514: TNS: 监听程序当前无法识别连接描述符中请求的服务
- How to configure CDB in Qt Creator(使用VC调试器)
- Java并发程序基础
- stringstream