之前在上一篇文章中多執行緒合集(二)---非同步的那些事,async和await原理拋析,我們從原始碼去分析了async和await如何執行,以及將編譯後的IL程式碼寫成了c#程式碼,以及實現自定義的Awaiter,自定義非同步狀態機同時將本系列的第一篇文章的自定義TaskScheduler和自定義的Awaiter結合起來,將程式碼跑了起來,而在c#10之後,我們可以實現自定義的非同步生成器,在上一篇文章中,我們將編譯後的程式碼還原成了c#程式碼,其中就有用到了一個AsyncTaskMethodBuilder的類,擱以前我們只能使用編譯器編譯之後的AsyncTaskMethodBuilder,現在我們已經可以自定義了,如果再加上上一章節的自定義狀態機,加排程,可能會更好玩一些,接下來就為大家奉上程式碼。
總共沒有多少程式碼,只是為了簡單的實現自定義的AsyncTaskMethodBuilder, 當然可能後續某位哥哥會用到將這些知識點串聯起來使用呢,可以看到,下面我們繼承了Task,實現了MyTask,此處演示效果,僅僅實現了一個建構函式以及一個GetAwaiter的方法,然後上面就是我們測試呼叫的Test方法,為什麼還需要new一個新的GetAwaiter呢,如果我們使用預設的TaskAwaiter,那你在Main方法await tes.Test的時候就會卡死的至於原因,就是await之後的程式碼等待結果是等待await之後的返回到上一層也就是說await後面的主動推結果,但是卡死是因為上一層卻主動找我要結果導致的卡死,導致我推不過去,上一層也找不到結果,此處我沒有具體分析,但是我的猜測是這樣,看官們可以自己嘗試一下,將MyTask的GetAwaiter註釋,使用預設的TaskAwaiter,然後呼叫Test方法,如果是await的時候肯定卡死,但是如果Task同步執行,也就是RunSynchronously這種方式執行,然後直接.Result,就可以獲取到結果,剛好可以驗證我上面的猜測,同一上下文了,不需要他主動推,但我可以主動獲取,
然後在往下面走就是我們自定義的一個Awaiter,實現介面後,建構函式的Func是我們返回結果的委託,這個結果是GetResult之後的結果值,OnCompleted方法和下面的Unsafe都是去推進狀態機告訴已經完了非同步的,上一章節說過這兩個方法的引數Action,實際上就是狀態機的MoveNext方法,最後就到了我們的自定義Builder實現,只需要遵循如下條件,官網列出的條件,既可以實現一個自定義的Builder,
// See https://aka.ms/new-console-template for more information using System.Reflection.PortableExecutable; using System.Runtime.CompilerServices; using System.Threading.Tasks; public class Program { static async Task Main(string[] args) { var tes = new TestAsync(); var task =await tes.Test(); Console.ReadKey(); } } public class TestAsync { public async MyTask<int> Test() { await MyTask<int>.Delay(1); return 100; } } [AsyncMethodBuilder(typeof(MyTaskBuilder<>))] public class MyTask<T> : Task<T> where T : notnull { public MyTask(Func<T> action) : base(action) { Action = action; } public Task<T> Task { get; } public Func<T> Action { get; } // // 摘要: // Gets an awaiter used to await this System.Threading.Tasks.Task`1. // // 返回結果: // An awaiter instance. public new CustomAwaiter<T> GetAwaiter() { var awaiter=new CustomAwaiter<T>(Action); return awaiter; } // 新增建構函式和其他功能程式碼 } public class CustomAwaiter<T> : ICriticalNotifyCompletion { public CustomAwaiter(Func<T> func) { Func = func; } public bool IsCompleted { get; set; } public Func<T> Func { get; } public void OnCompleted(Action continuation) { continuation(); IsCompleted = true; } public void UnsafeOnCompleted(Action continuation) { continuation(); IsCompleted = true; } public T GetResult() { return Func() ; } } public class MyTaskBuilder<T> where T:notnull { private readonly AsyncTaskMethodBuilder<T> _builder = new AsyncTaskMethodBuilder<T>(); private T Value; public static MyTaskBuilder<T> Create() { return new MyTaskBuilder<T>(); } public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { _builder.Start(ref stateMachine); } public void SetStateMachine(IAsyncStateMachine stateMachine) { _builder.SetStateMachine(stateMachine); } public void SetResult(T val) { Value = val; _builder.SetResult(val); } public void SetException(Exception exception) { _builder.SetException(exception); } public MyTask<T> Task { get { return new MyTask<T>(new Func<T>(() => Value)); } } public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine { _builder.AwaitOnCompleted(ref awaiter, ref stateMachine); } public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine { _builder.AwaitUnsafeOnCompleted(ref awaiter, ref stateMachine); } } public class StateMachine : IAsyncStateMachine { public StateMachine() { } public void MoveNext() { throw new NotImplementedException(); } public void SetStateMachine(IAsyncStateMachine stateMachine) { throw new NotImplementedException(); } }
自定義AsyncTaskMethodBuilder,需要滿足一下條件,即你定義的這個Builder類需要有Create方法,Task的屬性,SetException,設定異常的,SetResult設定結果的,以及一個Start的方法,同時在需要指定非同步Builder的類或者方法使用AsyncMethodBuilderArrtibute特性,裡面需要的引數就是你自定義Builder的type,即要麼在MyTask類上面使用此特性,也可以直接在Test方法上面新增此特性都可以實現自定義Builder,當然了此處有個擴充套件就是你可以參考上一章節的自定義狀態機,排程器,awaiter,自己手動實現編譯器編譯之後的程式碼,也就是下面這一段,當然了,內功深厚自己藉此實現一個簡單的非同步也是沒問題的,自己實現Task,類似我如上,繼承Task,然後藉助執行緒上下文等一些api,去實現一個自己的非同步也不是什麼難得事情,總之,此片文章實際上可能業務中會用不到,但是結合前幾篇,也可以更好的理解async和await了。
CustomAsyncStateMechine customAsyncStateMechine = new CustomAsyncStateMechine(); customAsyncStateMechine.builder = AsyncTaskMethodBuilder<string>.Create(); customAsyncStateMechine.State = -1; customAsyncStateMechine.builder.Start(ref customAsyncStateMechine); return customAsyncStateMechine.builder.Task;
今天水的一篇部落格就到這裡了,因為大家能更好的理解async和await,能夠將這些自定義的東西玩出花來,哈哈,關於async和await以及執行緒方面,感興趣的可以看看我之前的文章。