簡單實現(xiàn)C#異步操作
在.net4.0以后異步操作,并行計算變得異常簡單,但是由于公司項目開發(fā)基于.net3.5所以無法用到4.0的并行計算以及Task等異步編程。因此,為了以后更方便的進行異步方式的開發(fā),我封裝實現(xiàn)了異步編程框架,通過BeginInvoke、EndInvoke的方式實現(xiàn)異步編程。
一、框架結(jié)構(gòu)
整個框架包括四個部分
1、基類抽象Opeartor
我把每個異步執(zhí)行過程稱為一個Operate,因此需要一個Opeartor去執(zhí)行
2、FuncAsync
異步的Func
3、ActionAsync
異步的Action
4、Asynchorus
對ActionAsync和FuncAsync的封裝
Operator
Operator是一個抽象類,實現(xiàn)了IOperationAsync和IContinueWithAsync兩個接口。
IOperationAsync實現(xiàn)了異步操作,IContinueWithAsync實現(xiàn)了類似于Task的ContinueWith方法,在當(dāng)前異步操作完成后繼續(xù)進行的操作
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:前一個操作
Next:下一個操作
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;
}
}
無返回異步操作
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實現(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ǔ),接下來最重要的工作就是通過這兩個類執(zhí)行我們的異步操作,為此我封裝了一個異步操作類
主要封裝了以下幾個部分:
- WaitAll(IEnumerable<Operator> operations):等待所有操作執(zhí)行完畢
- WaitAny(IEnumerable<Operator> operations):等待任意操作執(zhí)行完畢
- ActionAsync
- FuncAsync
- ContinueWithAction
- ContinueWithFunc
后面四個包含若干個重載,這里只是籠統(tǒng)的代表一個類型的方法
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當(dāng)調(diào)用ContinueWithAsync后無法調(diào)用Wait等待,本來Wait需要從前往后等待每個異步操作,但是測試了下不符合預(yù)期結(jié)果。不過理論上來說應(yīng)該無需這樣操作,ContinueWithAsync只是為了當(dāng)上一個異步操作執(zhí)行完畢時繼續(xù)執(zhí)行的異步操作,若要等待,那不如兩個操作放到一起,最后再等待依然可以實現(xiàn)。
前面的都是單步異步操作的調(diào)用,若需要對某集合進行某個方法的異步操作,可以foreach遍歷
public void ForeachAsync(IEnumerbale<string> parameters)
{
foreach(string p in parameters)
{
Asynchronous.Invoke(Tast,p);
}
}
public void Test(string parameter)
{
//TODO:做一些事
}
每次都需要去手寫foreach,比較麻煩,因此實現(xiàn)類似于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();
}
如何使用
無返回值異步方法調(diào)用
public void DoSomeThing()
{
//TODO:
}
通過Asynchronous.Invoke(DoSomeThing) 執(zhí)行
public void DoSomeThing(string parameter)
{
//TODO:
}
通過Asynchronous.Invoke(DoSomeThing,parameter) 執(zhí)行
有返回值異步方法調(diào)用
public string DoSomeThing()
{
//TODO:
}
通過Asynchronous.Invoke(()=>DoSomeThing())執(zhí)行
public string DoSomeThing(string parameter)
{
//TODO:
}
通過Asynchronous.Invoke(()=>DoSomeThing(parameter))執(zhí)行,或者也可以傳入?yún)?shù)通過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倍,然后輸出
異步執(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í)行
可能有時候我們需要遍歷一個集合,每個元素處理完成后我們需要輸出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(()={
//每個元素執(zhí)行完時執(zhí)行
if(o.Exception != null)
{
//之前執(zhí)行時產(chǎn)生未處理的異常,這里可以捕獲到
}
});
});
}
可以實現(xiàn)鏈?zhǔn)疆惒讲僮?/strong>
public void Chain()
{
Asynchronous.Invoke(Console.WriteLine,1)
.ContinueWithAsync(Console.WriteLine,2)
.ContinueWithAsync(Console.WriteLine,3)
}
這樣會按步驟輸出1,2,3
結(jié)束語
以上只是列出了部分重載方法,其他重載方法無非就是加參數(shù),本質(zhì)實際是一樣的。
希望對大家的學(xué)習(xí)有所幫助,在這祝大家新年快樂,新的一年大家一起努力。
上一篇:詳解C#的設(shè)計模式編程之抽象工廠模式的應(yīng)用
欄 目:C#教程
本文標(biāo)題:簡單實現(xiàn)C#異步操作
本文地址:http://www.jygsgssxh.com/a1/C_jiaocheng/6700.html
您可能感興趣的文章
- 01-10C#實現(xiàn)txt定位指定行完整實例
- 01-10WinForm實現(xiàn)仿視頻播放器左下角滾動新聞效果的方法
- 01-10C#實現(xiàn)清空回收站的方法
- 01-10C#實現(xiàn)讀取注冊表監(jiān)控當(dāng)前操作系統(tǒng)已安裝軟件變化的方法
- 01-10C#實現(xiàn)多線程下載文件的方法
- 01-10C#實現(xiàn)Winform中打開網(wǎng)頁頁面的方法
- 01-10C#實現(xiàn)遠程關(guān)閉計算機或重啟計算機的方法
- 01-10C#自定義簽名章實現(xiàn)方法
- 01-10C#文件斷點續(xù)傳實現(xiàn)方法
- 01-10winform實現(xiàn)創(chuàng)建最前端窗體的方法


閱讀排行
本欄相關(guān)
- 01-10C#通過反射獲取當(dāng)前工程中所有窗體并
- 01-10關(guān)于ASP網(wǎng)頁無法打開的解決方案
- 01-10WinForm限制窗體不能移到屏幕外的方法
- 01-10WinForm繪制圓角的方法
- 01-10C#實現(xiàn)txt定位指定行完整實例
- 01-10WinForm實現(xiàn)仿視頻播放器左下角滾動新
- 01-10C#停止線程的方法
- 01-10C#實現(xiàn)清空回收站的方法
- 01-10C#通過重寫Panel改變邊框顏色與寬度的
- 01-10C#實現(xiàn)讀取注冊表監(jiān)控當(dāng)前操作系統(tǒng)已
隨機閱讀
- 01-10delphi制作wav文件的方法
- 01-11ajax實現(xiàn)頁面的局部加載
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-10C#中split用法實例總結(jié)
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 04-02jquery與jsp,用jquery


