簡(jiǎn)單實(shí)現(xiàn)C#異步操作
在.net4.0以后異步操作,并行計(jì)算變得異常簡(jiǎn)單,但是由于公司項(xiàng)目開(kāi)發(fā)基于.net3.5所以無(wú)法用到4.0的并行計(jì)算以及Task等異步編程。因此,為了以后更方便的進(jìn)行異步方式的開(kāi)發(fā),我封裝實(shí)現(xiàn)了異步編程框架,通過(guò)BeginInvoke、EndInvoke的方式實(shí)現(xiàn)異步編程。
一、框架結(jié)構(gòu)
整個(gè)框架包括四個(gè)部分
1、基類(lèi)抽象Opeartor
我把每個(gè)異步執(zhí)行過(guò)程稱(chēng)為一個(gè)Operate,因此需要一個(gè)Opeartor去執(zhí)行
2、FuncAsync
異步的Func
3、ActionAsync
異步的Action
4、Asynchorus
對(duì)ActionAsync和FuncAsync的封裝
Operator
Operator是一個(gè)抽象類(lèi),實(shí)現(xiàn)了IOperationAsync和IContinueWithAsync兩個(gè)接口。
IOperationAsync實(shí)現(xiàn)了異步操作,IContinueWithAsync實(shí)現(xiàn)了類(lèi)似于Task的ContinueWith方法,在當(dāng)前異步操作完成后繼續(xù)進(jìn)行的操作
IOperationAsync接口詳解
public interface IOperationAsync { IAsyncResult Invoke(); void Wait(); void CompletedCallBack(IAsyncResult ar); void CatchException(Exception exception); }
- Invoke():異步方法的調(diào)用
- Wait():等待異步操作執(zhí)行
- CompletedCallBack():操作完成回調(diào)
- 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:前一個(gè)操作
Next:下一個(gè)操作
ContinueWithAsync():異步繼續(xù)操作
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; } }
無(wú)返回異步操作
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實(shí)現(xiàn)了IFuncOperationAsync接口
IFuncOperationAsync
public interface IFuncOperationAsync<T> { void SetResult(T result); T GetResult(); }
- SetResult(T result):異步操作完成設(shè)置返回值
- 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, 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為異步操作打下了基礎(chǔ),接下來(lái)最重要的工作就是通過(guò)這兩個(gè)類(lèi)執(zhí)行我們的異步操作,為此我封裝了一個(gè)異步操作類(lèi)
主要封裝了以下幾個(gè)部分:
- WaitAll(IEnumerable<Operator> operations):等待所有操作執(zhí)行完畢
- WaitAny(IEnumerable<Operator> operations):等待任意操作執(zhí)行完畢
- ActionAsync
- FuncAsync
- ContinueWithAction
- ContinueWithFunc
后面四個(gè)包含若干個(gè)重載,這里只是籠統(tǒng)的代表一個(gè)類(lèi)型的方法
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); }
等待時(shí)間可以自定義
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); }
這里有個(gè)bug當(dāng)調(diào)用ContinueWithAsync后無(wú)法調(diào)用Wait等待,本來(lái)Wait需要從前往后等待每個(gè)異步操作,但是測(cè)試了下不符合預(yù)期結(jié)果。不過(guò)理論上來(lái)說(shuō)應(yīng)該無(wú)需這樣操作,ContinueWithAsync只是為了當(dāng)上一個(gè)異步操作執(zhí)行完畢時(shí)繼續(xù)執(zhí)行的異步操作,若要等待,那不如兩個(gè)操作放到一起,最后再等待依然可以實(shí)現(xiàn)。
前面的都是單步異步操作的調(diào)用,若需要對(duì)某集合進(jìn)行某個(gè)方法的異步操作,可以foreach遍歷
public void ForeachAsync(IEnumerbale<string> parameters) { foreach(string p in parameters) { Asynchronous.Invoke(Tast,p); } } public void Test(string parameter) { //TODO:做一些事 }
每次都需要去手寫(xiě)foreach,比較麻煩,因此實(shí)現(xiàn)類(lèi)似于PLinq的并行計(jì)算方法實(shí)在有必要,不過(guò)有一點(diǎn)差別,PLinq是采用多核CPU進(jìn)行并行計(jì)算,而我封裝的僅僅遍歷集合進(jìn)行異步操作而已
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(); }
如何使用
無(wú)返回值異步方法調(diào)用
public void DoSomeThing() { //TODO: }
通過(guò)Asynchronous.Invoke(DoSomeThing) 執(zhí)行
public void DoSomeThing(string parameter) { //TODO: }
通過(guò)Asynchronous.Invoke(DoSomeThing,parameter) 執(zhí)行
有返回值異步方法調(diào)用
public string DoSomeThing() { //TODO: }
通過(guò)Asynchronous.Invoke(()=>DoSomeThing())執(zhí)行
public string DoSomeThing(string parameter) { //TODO: }
通過(guò)Asynchronous.Invoke(()=>DoSomeThing(parameter))執(zhí)行,或者也可以傳入?yún)?shù)通過(guò)Asynchronous.Invoke(p=>DoSomeThing(p),parameter)
無(wú)返回值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)); }
首先將集合每個(gè)值擴(kuò)大2倍,然后輸出
異步執(zhí)行完再執(zhí)行
public void Test { int[] parameters = {1,2,3,4,5}; var operators = Asynchronous.Foreach(parameters,p=> p*2); Asynchrous.ContinueWithAsync(operators,Console.WriteLine,"執(zhí)行完成"); }
每次執(zhí)行完繼續(xù)執(zhí)行
可能有時(shí)候我們需要遍歷一個(gè)集合,每個(gè)元素處理完成后我們需要輸出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(()={ //每個(gè)元素執(zhí)行完時(shí)執(zhí)行 if(o.Exception != null) { //之前執(zhí)行時(shí)產(chǎn)生未處理的異常,這里可以捕獲到 } }); }); }
可以實(shí)現(xiàn)鏈?zhǔn)疆惒讲僮?/strong>
public void Chain() { Asynchronous.Invoke(Console.WriteLine,1) .ContinueWithAsync(Console.WriteLine,2) .ContinueWithAsync(Console.WriteLine,3) }
這樣會(huì)按步驟輸出1,2,3
結(jié)束語(yǔ)
以上只是列出了部分重載方法,其他重載方法無(wú)非就是加參數(shù),本質(zhì)實(shí)際是一樣的。
希望對(duì)大家的學(xué)習(xí)有所幫助,在這祝大家新年快樂(lè),新的一年大家一起努力。
相關(guān)文章
C#自定義的字符串操作增強(qiáng)類(lèi)實(shí)例
這篇文章主要介紹了C#自定義的字符串操作增強(qiáng)類(lèi),涉及C#操作字符串實(shí)現(xiàn)分割、轉(zhuǎn)換、去重等常用技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-03-03Unity C#打包AssetBundle與場(chǎng)景詳解
這篇文章主要給大家介紹了關(guān)于Unity C#打包AssetBundle與場(chǎng)景的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02c#泛型序列化對(duì)象為字節(jié)數(shù)組的示例
這篇文章主要介紹了c#泛型序列化對(duì)象為字節(jié)數(shù)組的示例,需要的朋友可以參考下2014-04-04基于Unity實(shí)現(xiàn)3D版2048游戲的示例代碼
這篇文章主要為大家詳細(xì)介紹了如何利用Unity實(shí)現(xiàn)簡(jiǎn)易的3D版2048游戲,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,需要的可以參考一下2023-02-02C#表達(dá)式樹(shù)Expression動(dòng)態(tài)創(chuàng)建表達(dá)式
這篇文章介紹了C#表達(dá)式樹(shù)Expression動(dòng)態(tài)創(chuàng)建表達(dá)式的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-12-12C#中TreeView節(jié)點(diǎn)的自定義繪制方法
這篇文章主要介紹了C#中TreeView節(jié)點(diǎn)的自定義繪制方法,實(shí)例展示了TreeView節(jié)點(diǎn)的操作技巧,需要的朋友可以參考下2015-02-02C#中動(dòng)態(tài)數(shù)組用法實(shí)例
這篇文章主要介紹了C#中動(dòng)態(tài)數(shù)組用法,實(shí)例分析了C#中ArrayList實(shí)現(xiàn)動(dòng)態(tài)數(shù)組的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04C#8.0 中開(kāi)啟默認(rèn)接口實(shí)現(xiàn)方法
這篇文章主要介紹了C#8.0 中開(kāi)啟默認(rèn)接口實(shí)現(xiàn)方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧的相關(guān)資料2019-05-05