欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#異步編程async/await用法詳解

 更新時(shí)間:2022年01月26日 11:48:17   作者:痕跡g  
本文詳細(xì)講解了C#異步編程async/await的用法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

異步函數(shù)簡(jiǎn)介

一般指 async 修飾符聲明得、可包含await表達(dá)式得方法或匿名函數(shù)。

聲明方式

異步方法的聲明語(yǔ)法與其他方法完全一樣, 只是需要包含 async 關(guān)鍵字。async可以出現(xiàn)在返回值之前的任何位置, 如下示例:

        async public static void GetInfoAsync()
        {
           //...
        }

        public async static void GetInfoAsync()
        {
           //...
        }

        public static async void GetInfoAsync()
        {
            //...
        }

異步方法的返回類型

異步函數(shù)的返回類型只能為: void、Task、Task<TResult>。

Task<TResult>: 代表一個(gè)返回值T類型的操作。

Task: 代表一個(gè)無(wú)返回值的操作。

void: 為了和傳統(tǒng)的事件處理程序兼容而設(shè)計(jì)。

await(等待)

await等待的是什么? 可以是一個(gè)異步操作(Task)、亦或者是具備返回值的異步操作(Task<TResult>)的值, 如下:

        public async static void GetInfoAsync()
        {
            await GetData(); // 等待異步操作, 無(wú)返回值
            await GetData<int>(1); //等待異步操作, 返回值 int
        }

        static Task GetData()
        {
            //...
            return null;
        }

        static Task<T> GetData<T>(int a)
        {
            //...
            return null;
        }

注: await 最終操作的是一個(gè)值, 當(dāng)然, 也可以是無(wú)值, 如上GetData() , 否則就是一個(gè) Task<T> 如上: GetData<T>()

await執(zhí)行過(guò)程

TaskAwaiter 獲取執(zhí)行結(jié)果

一般而言, await等待的一個(gè)異步操作, 無(wú)論是具備返回值還是否, 那么最終都會(huì)獲得該操作是否已完成、具備返回值得異步操作可以獲取他得返回結(jié)果。

所以這個(gè)時(shí)候,TaskAwaiter出現(xiàn)了, 無(wú)論是Task、還是Task<TResult>操作, 都具備GetAwaiter() 方法。

用于獲取改操作得狀態(tài)、返回結(jié)果, 及部分操作, 如下TaskAwaiter結(jié)構(gòu):

    //
    // 摘要:
    //     提供等待異步任務(wù)完成的對(duì)象。
    public struct TaskAwaiter : ICriticalNotifyCompletion, INotifyCompletion
    {
        //
        // 摘要:
        //     獲取一個(gè)值,該值指示是否已完成的異步任務(wù)。
        //
        // 返回結(jié)果:
        //     true 如果任務(wù)已完成;否則為 false。
        //
        // 異常:
        //   T:System.NullReferenceException:
        //     System.Runtime.CompilerServices.TaskAwaiter 對(duì)象未正確初始化。
        public bool IsCompleted { get; }

        //
        // 摘要:
        //     結(jié)束異步任務(wù)完成之前的等待。
        //
        // 異常:
        //   T:System.NullReferenceException:
        //     System.Runtime.CompilerServices.TaskAwaiter 對(duì)象未正確初始化。
        //
        //   T:System.Threading.Tasks.TaskCanceledException:
        //     任務(wù)已取消。
        //
        //   T:System.Exception:
        //     在完成的任務(wù) System.Threading.Tasks.TaskStatus.Faulted 狀態(tài)。
        [TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
        public void GetResult();
        //
        // 摘要:
        //     設(shè)置時(shí)應(yīng)執(zhí)行的操作 System.Runtime.CompilerServices.TaskAwaiter 對(duì)象停止等待異步任務(wù)完成。
        //
        // 參數(shù):
        //   continuation:
        //     要在等待操作完成時(shí)執(zhí)行的操作。
        //
        // 異常:
        //   T:System.ArgumentNullException:
        //     continuation 為 null。
        //
        //   T:System.NullReferenceException:
        //     System.Runtime.CompilerServices.TaskAwaiter 對(duì)象未正確初始化。
        [SecuritySafeCritical]
        public void OnCompleted(Action continuation);
        //
        // 摘要:
        //     計(jì)劃程序與此等待異步任務(wù)的延續(xù)任務(wù)操作。
        //
        // 參數(shù):
        //   continuation:
        //     要等待操作完成時(shí)調(diào)用的操作。
        //
        // 異常:
        //   T:System.ArgumentNullException:
        //     continuation 為 null。
        //
        //   T:System.InvalidOperationException:
        //     該等待程序未正確初始化。
        [SecurityCritical]
        public void UnsafeOnCompleted(Action continuation);
    }

接下來(lái), 演示如何通過(guò)等待去獲取異步操作的返回結(jié)果, 如下代碼所示:

        public async static void GetInfoAsync()
        {
            Task<bool> task = Task.Run<bool>(() =>
            {
                Thread.Sleep(10000); //模擬耗時(shí)
                return true;
            });
            
            //以下兩種方式
            bool taskResult1 = await task;  //內(nèi)部自己執(zhí)行了GetAwaiter() 
            bool taskResult = task.GetAwaiter().GetResult();  //自己手動(dòng)執(zhí)行Awaiter(), 但是阻塞UI
       Console.WriteLine(taskResult);
        }

注: 對(duì)于一個(gè)await表達(dá)式, 編譯器生成的代碼會(huì)先調(diào)用GetAwaiter(), 然后通過(guò)awaiter得成員來(lái)等待結(jié)果, 所以以上兩種方式等效( 不考慮阻塞的情況下)

為了驗(yàn)證以上猜測(cè), 通過(guò)反編譯工具查看得到如下代碼:

編譯器最終生成兩個(gè)密封類, 一個(gè)類( <>c )我們展開(kāi)分析:

<GetInfoAsync>b__1_0() 正是模擬耗時(shí)的一個(gè)操作委托生成的方法。

        [CompilerGenerated]
        [Serializable]
        private sealed class <>c
        {
            public static readonly Program.<>c <>9 = new Program.<>c();
            public static Func<bool> <>9__1_0;
            internal bool <GetInfoAsync>b__1_0()
            {
                Thread.Sleep(10000);
                return true;
            }
        }

第二個(gè)類<GetInfoAsync>d__1 分析:

該類分別實(shí)現(xiàn)了接口 IAsyncStateMachine 的MoveNext() 與 SetStateMachine() ,另外 注意,

還特別定義了一個(gè) <>t__builder, 先記住他, 下面講會(huì)對(duì)他講到, 為什么編譯器生成的代碼會(huì)默認(rèn)先調(diào)用GetAwaiter()

 [CompilerGenerated]
         private sealed class <GetInfoAsync>d__1 : IAsyncStateMachine
         {
             public int <>1__state;
             public AsyncVoidMethodBuilder <>t__builder;
             private Task<bool> <task>5__1;
             private bool <result>5__2;
             private bool <>s__3;
             private TaskAwaiter<bool> <>u__1;
             void IAsyncStateMachine.MoveNext()
             {
                 int num = this.<>1__state;
                 try
                 {
                     TaskAwaiter<bool> awaiter;
                     if (num != 0)
                     {
                         Func<bool> arg_2F_0;
                         if ((arg_2F_0 = Program.<>c.<>9__1_0) == null)
                         {
                             arg_2F_0 = (Program.<>c.<>9__1_0 = new Func<bool>(Program.<>c.<>9.<GetInfoAsync>b__1_0));
                         }
                         this.<task>5__1 = Task.Run<bool>(arg_2F_0);
                         awaiter = this.<task>5__1.GetAwaiter();
                         if (!awaiter.IsCompleted)
                         {
                             this.<>1__state = 0;
                             this.<>u__1 = awaiter;
                             Program.<GetInfoAsync>d__1 <GetInfoAsync>d__ = this;
                             this.<>t__builder.AwaitUnsafeOnCompleted<TaskAwaiter<bool>, Program.<GetInfoAsync>d__1>(ref awaiter, ref <GetInfoAsync>d__);
                             return;
                         }
                     }
                     else
                     {
                         awaiter = this.<>u__1;
                         this.<>u__1 = default(TaskAwaiter<bool>);
                         this.<>1__state = -1;
                     }
                     this.<>s__3 = awaiter.GetResult();
                     this.<result>5__2 = this.<>s__3;
                     Console.WriteLine(this.<result>5__2);
                 }
                 catch (Exception exception)
                 {
                     this.<>1__state = -2;
                     this.<>t__builder.SetException(exception);
                     return;
                 }
                 this.<>1__state = -2;
                 this.<>t__builder.SetResult();
             }
             [DebuggerHidden]
             void IAsyncStateMachine.SetStateMachine(IAsyncStateMachine stateMachine)
             {
             }
         }

接下來(lái), 看GetInfoAsync()方法, 這個(gè)是自己編寫(xiě)的, 但是實(shí)現(xiàn)的細(xì)節(jié),最終轉(zhuǎn)換成了編譯器執(zhí)行代碼:

        [AsyncStateMachine(typeof(Program.<GetInfoAsync>d__1)), DebuggerStepThrough]
        public static void GetInfoAsync()
        {
            Program.<GetInfoAsync>d__1 <GetInfoAsync>d__ = new Program.<GetInfoAsync>d__1();
            <GetInfoAsync>d__.<>t__builder = AsyncVoidMethodBuilder.Create();
            <GetInfoAsync>d__.<>1__state = -1;
            AsyncVoidMethodBuilder <>t__builder = <GetInfoAsync>d__.<>t__builder;
            <>t__builder.Start<Program.<GetInfoAsync>d__1>(ref <GetInfoAsync>d__); //注意到該代碼, 調(diào)用了Start(),也許這就是默認(rèn)實(shí)現(xiàn)的地方
        }

通過(guò)查看Start泛型方法的實(shí)現(xiàn), 最終找到了, 該泛型的條件限制于必須實(shí)現(xiàn)與IAsyncStateMachine 接口, 所以通過(guò)查看, 該類最終調(diào)用了 MoveNext(), 而MoveNext中正

調(diào)用了GetAwaiter()。關(guān)于Start的實(shí)現(xiàn)如下所示:

[SecuritySafeCritical, DebuggerStepThrough, __DynamicallyInvokable]
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine
{
    if (stateMachine == null)
    {
        throw new ArgumentNullException("stateMachine");
    }
    ExecutionContextSwitcher executionContextSwitcher = default(ExecutionContextSwitcher);
    RuntimeHelpers.PrepareConstrainedRegions();
    try
    {
        ExecutionContext.EstablishCopyOnWriteScope(ref executionContextSwitcher);
        stateMachine.MoveNext();
    }
    finally
    {
        executionContextSwitcher.Undo();
    }
}

剖析MoveNext

對(duì)比IDE中的代碼, 如下所示:

總結(jié)

await等待的是任務(wù)的操作值, 最終返回是異步操作的返回結(jié)果。而這一切都是因?yàn)榫幾g器創(chuàng)建了一系列復(fù)雜的狀態(tài)機(jī)制, 以達(dá)到其實(shí)現(xiàn)。

到此這篇關(guān)于C#異步編程async/await用法詳解的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論