After .net4.0, parallel computing became extremely simple, but because the company's project development was based on .net3.5, parallel computing and asynchronous programming such as Task could not be used. Therefore, in order to more conveniently develop asynchronous methods in the future, I encapsulated and implemented the asynchronous programming framework, and implemented asynchronous programming through BeginInvoke and EndInvoke.
1. Framework structure
The entire framework consists of four parts
1. Base class abstract operator
I call each asynchronous execution process an Operate, so an Operator is needed to execute
2、FuncAsync
Asynchronous Func
3、ActionAsync
Asynchronous Action
4、Asynchorus
Encapsulation of ActionAsync and FuncAsync
Operator
Operator is an abstract class that implements two interfaces: IOperationAsync and IContinueWithAsync.
IOperationAsync implements asynchronous operations, IContinueWithAsync implements ContinueWith method similar to Task, which continues after the current asynchronous operation is completed.
Detailed explanation of IOperationAsync interface
public interface IOperationAsync { IAsyncResult Invoke(); void Wait(); void CompletedCallBack(IAsyncResult ar); void CatchException(Exception exception); }
- Invoke(): Calling of asynchronous method
- Wait(): Wait for asynchronous operation to execute
- CompletedCallBack(): The operation completes the callback
- CatchException(): Catch exception
IContinueWithAsync interface details
public interface IContinueWithAsync { Operator Previous { get; set; } Operator Next { get; set; } Operator ContinueWithAsync(Action action); Operator ContinueWithAsync<TParameter>(Action<TParameter> action, TParameter parameter); }
Previous: Previous operation
Next:Next operation
ContinueWithAsync(): Continue operation asynchronously
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 = ().ToString(); } public abstract IAsyncResult Invoke(); protected void SetAsyncResult(IAsyncResult result) { = result; } public virtual void Wait() { if (!) (); } public virtual void CompletedCallBack(IAsyncResult ar) { } public void CatchException(Exception exception) { = exception; } protected Operator ContinueAsync() { if (Next != null) (); return Next; } public virtual Operator ContinueWithAsync(Action action) { Next = new ActionAsync(action); = this; return Next; } public virtual Operator ContinueWithAsync<TParameter>(Action<TParameter> action, TParameter parameter) { Next = new ActionAsync<TParameter>(action, parameter); = this; return Next; } public virtual Operator ContinueWithAsync<TResult>(Func<TResult> func) { Next = new FuncAsync<TResult>(); = this; return Next; } public virtual Operator ContinueWithAsync<TParameter, TResult>(Func<TParameter, TResult> func, TParameter parameter) { Next = new FuncAsync<TParameter, TResult>(func, parameter); = this; return Next; } }
No return asynchronous operation
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) { (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) { (exception); } ContinueAsync(); } }
There is a return asynchronous
FuncAsync implements IFuncOperationAsync interface
IFuncOperationAsync
public interface IFuncOperationAsync<T> { void SetResult(T result); T GetResult(); }
- SetResult(T result): Set return value after completion of asynchronous operation
- GetResult(): Get the return value
1)、FuncAsync
public class FuncAsync<TResult> : Operator, IFuncOperationAsync<TResult> { private TResult _result; public TResult Result { get { if (! || _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) { (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 asynchronous operation encapsulation
ActionAsync and FuncAsync have laid the foundation for asynchronous operations. The most important thing next is to perform our asynchronous operations through these two classes. For this reason, I encapsulate an asynchronous operation class.
The following parts are mainly encapsulated:
- WaitAll(IEnumerable<Operator> operations): WaitAll(IEnumerable<Operator> operations): WaitAll
- WaitAny(IEnumerable<Operator> operations): WaitAny(IEnumerable<Operator> operations): WaitAny(IEnumerable<Operator> operations): WaitAny(IEnumerable<Operator> operations): WaitAny(IEnumerable<Operator> operations): WaitAny(IEnumerable<Operator> operations): WaitAny(IEnumerable<Operator> operations): WaitAny(IEnumerable<Operator> operations): WaitAny(IEnumerable<Operator> operations): WaitAny(IEnumerable<Operator> operations): WaitAny(IEnumerable<Operator> operations): WaitAny(IEnumerable<Operator> operations): WaitAny(IEnumerable<Operator> operations): WaitAny(IEnumerable<Operator> operations): WaitAny(IEnumerable<Operator> operations):
- ActionAsync
- FuncAsync
- ContinueWithAction
- ContinueWithFunc
The last four contain several overloads, here is just a general method that represents a type of method.
WaitAll
public static void WaitAll(IEnumerable<Operator> operations) { foreach (var @operator in operations) { @(); } }
WaitAny
public static void WaitAny(IEnumerable<Operator> operations) { while ((o => !)) (100); }
Waiting time can be customized
ActionInvoke
public static Operator Invoke(Action action) { Operator operation = new ActionAsync(action); (); return operation; } public static Operator Invoke<T>(Action<T> action, T parameter) { Operator operation = new ActionAsync<T>(action, parameter); (); 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); (); return operation; }
FuncInvoke
public static Operator Invoke<TResult>(Func<TResult> func) { Operator operation = new FuncAsync<TResult>(func); (); 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); (); 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); (); 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); }
There is a bug here. When ContinueWithAsync is called, Wait cannot be called. Wait originally needed to wait for each asynchronous operation from front to back, but the test did not meet the expected results. However, in theory, there should be no need to operate like this. ContinueWithAsync is just an asynchronous operation that continues to be executed when the previous asynchronous operation is completed. If you want to wait, it is better to put the two operations together and wait in the end, it can still be implemented.
The previous ones are all calls for single-step asynchronous operations. If you need to perform asynchronous operations on a certain set, you can foreach traversal.
public void ForeachAsync(IEnumerbale<string> parameters) { foreach(string p in parameters) { (Tast,p); } } public void Test(string parameter) { //TODO: Do something}
Every time I need to write foreach, which is quite troublesome, so it is really necessary to implement parallel computing methods similar to PLinq. However, there is a little difference. PLinq uses multi-core CPU for parallel computing, while the encapsulation only traversal sets for asynchronous operations.
ForeachAction
public static IEnumerable<Operator> Foreach<TParameter>(IEnumerable<TParameter> items, Action<TParameter> action) { return (t => Invoke(action, t)).ToList(); }
ForeachFunc
public static IEnumerable<Operator> Foreach<TParameter, TResult>(IEnumerable<TParameter> items, Func<TParameter, TResult> func) { return (parameter => Invoke(func, parameter)).ToList(); }
How to use
Asynchronous method call without return value
public void DoSomeThing() { //TODO: }
Execute via (DoSomeThing)
public void DoSomeThing(string parameter) { //TODO: }
Execute via (DoSomeThing, parameter)
Asynchronous method call with return value
public string DoSomeThing() { //TODO: }
Execute via (()=>DoSomeThing())
public string DoSomeThing(string parameter) { //TODO: }
Execute through (()=>DoSomeThing(parameter)), or you can pass in parameters through (p=>DoSomeThing(p), parameter)
No return value Foreach
public void Test { int[] parameters = {1,2,3,4,5}; (parameters,); }
There is a return value for Foreach
public void Test { int[] parameters = {1,2,3,4,5}; var operators = (parameters,p=> p*2); (operators); (<FuncAsync<int,int>>(), p=> ()); }
First expand each value of the set by 2 times, and then output
Execute asynchronously
public void Test { int[] parameters = {1,2,3,4,5}; var operators = (parameters,p=> p*2); (operators,,"Execution Completed"); }
Continue execution every time
Maybe sometimes we need to traverse a collection, and after each element is processed, we need to output XX to complete the process.
public void Test { int[] parameters = {1,2,3,4,5}; var operators = (parameters,p=> p*2); (operators,o=>{ (()={ //Execute when each element is executed if( != null) { //Unhandled exception was generated during previous execution, which can be caught here } }); }); }
Can implement chain asynchronous operation
public void Chain() { (,1) .ContinueWithAsync(,2) .ContinueWithAsync(,3) }
This will output 1, 2, 3 according to the steps
Conclusion
The above only lists some of the overloaded methods. Other overloaded methods are nothing more than adding parameters, and the essence is actually the same.
I hope it will be helpful to everyone’s learning. I wish you a happy new year and work hard together in the new year.