多執行緒合集(三)---非同步的那些事之自定義AsyncTaskMethodBuilder

2023-05-25 12:00:56

引言    

    之前在上一篇文章中多執行緒合集(二)---非同步的那些事,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();
    }
}

自定義Builder的條件

    自定義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以及執行緒方面,感興趣的可以看看我之前的文章。