日韩欧美人妻无码精品白浆,夜夜嗨AV免费入口,国产欧美官网在线看,高校回应聋哑女生因长相完美被质疑

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開(kāi)發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

聊一聊 C#異步 任務(wù)延續(xù)的三種底層玩法

freeflydom
2025年1月10日 8:50 本文熱度 987

一:背景

1. 講故事

最近聊了不少和異步相關(guān)的話題,有點(diǎn)疲倦了,今天再寫最后一篇作為近期這類話題的一個(gè)封筆吧,下篇繼續(xù)寫我熟悉的 生產(chǎn)故障 系列,突然親切感油然而生,哈哈,免費(fèi)給別人看程序故障,是一種積陰德陽(yáng)善的事情,欲知前世因,今生受者是。欲知來(lái)世果,今生做者是。

在任務(wù)延續(xù)方面,我個(gè)人的總結(jié)就是三類,分別為:

  1. StateMachine
  2. ContinueWith
  3. Awaiter

話不多說(shuō),我們逐個(gè)研究下底層是咋玩的?

二:異步任務(wù)延續(xù)的玩法

1. StateMachine

說(shuō)到狀態(tài)機(jī)大家再熟悉不過(guò)了,也是 async,await 的底層化身,很多人看到 async await 就想到了IO場(chǎng)景,其實(shí)IO場(chǎng)景和狀態(tài)機(jī)是兩個(gè)獨(dú)立的東西,狀態(tài)機(jī)是一種設(shè)計(jì)模式,把這個(gè)模式套在IO場(chǎng)景會(huì)讓代碼更加絲滑,僅此而已。為了方便講述,我們寫一個(gè) StateMachine 與 IO場(chǎng)景 無(wú)關(guān)的一段測(cè)試代碼。


    internal class Program
    {
        static void Main(string[] args)
        {
            UseAwaitAsync();
            Console.ReadLine();
        }
        static async Task<string> UseAwaitAsync()
        {
            var html = await Task.Run(() =>
            {
                Thread.Sleep(1000);
                var response = "<html><h1>博客園</h1></html>";
                return response;
            });
            Console.WriteLine($"GetStringAsync 的結(jié)果:{html}");
            return html;
        }
    }

那這段代碼在底層是如何運(yùn)作的呢?剛才也說(shuō)到了asyncawait只是迷惑你的一種幻象,我們必須手握辟邪寶劍斬開(kāi)幻象顯真身,這里借助 ilspy 截圖如下:

從卦中看,本質(zhì)上就是借助AsyncTaskMethodBuilder<string> 建造者將 awaiter 和 stateMachine 做了一個(gè)綁定,感興趣的朋友可以追一下 AwaitUnsafeOnCompleted() 方法,最后狀態(tài)機(jī) <UseAwaitAsync>d__1 實(shí)例會(huì)放入到 Task.Run 的 m_continuationObject 字段。如果有朋友對(duì)流程比較蒙的話,我畫了一張簡(jiǎn)圖。

圖和代碼都有了,接下來(lái)就是眼見(jiàn)為實(shí)。分別在 AddTaskContinuation 和 RunContinuations 方法中做好埋點(diǎn),前者可以看到 延續(xù)任務(wù) 是怎么加進(jìn)去的,后者可以看到 延續(xù)任務(wù) 是怎么取出來(lái)的。


心細(xì)的朋友會(huì)發(fā)現(xiàn)這卦上有一個(gè)很特別的地方,就是 allowInlining=true,也就是回調(diào)函數(shù)(StateMachine)是在當(dāng)前線程上一擼到底的。

有些朋友可能要問(wèn),能不能讓延續(xù)任務(wù) 跑在單獨(dú)線程上? 可以是可以,但你得把 Task.Run 改成 Task.Factory.StartNew ,這樣就可以設(shè)置TaskCreationOptions參數(shù),參考代碼如下:

    var html = await Task.Factory.StartNew(() =>{}, TaskCreationOptions.RunContinuationsAsynchronously);

2. ContinueWith

那些同處于被裁的35歲大齡程序員應(yīng)該知道Task是 framework 4.0 時(shí)代出來(lái)的,而async,await是4.5出來(lái)的,所以在這個(gè)過(guò)渡期中有大量的項(xiàng)目會(huì)使用ContinueWith 導(dǎo)致回調(diào)地獄。。。 這里我們對(duì)比一下兩者有何不同,先寫一段參考代碼。


    internal class Program
    {
        static void Main(string[] args)
        {
            UseContinueWith();
            Console.ReadLine();
        }
        static Task<string> UseContinueWith()
        {
            var query = Task.Run(() =>
            {
                Thread.Sleep(1000);
                var response = "<html><h1>博客園</h1></html>";
                return response;
            }).ContinueWith(t =>
            {
                var html = t.Result;
                Console.WriteLine($"GetStringAsync 的結(jié)果:{html}");
                return html;
            });
            return query;
        }
    }

從卦代碼看確實(shí)沒(méi)有asyncawait簡(jiǎn)潔,那 ContinueWith 內(nèi)部做了什么呢?感興趣的朋友可以跟蹤一下,本質(zhì)上和 StateMachine 的玩法是一樣的,都是借助 m_continuationObject 來(lái)實(shí)現(xiàn)延續(xù),畫個(gè)簡(jiǎn)圖如下:

代碼和模型圖都有了,接下來(lái)就是用 dnspy 開(kāi)干了。。。還是在 AddTaskContinuation 和 RunContinuations 上埋伏斷點(diǎn)觀察。


從卦中可以看到,延續(xù)任務(wù)使用新線程來(lái)執(zhí)行的,并沒(méi)有一擼到底,這明顯與 asyncawait 的方式不同,有些朋友可能又要說(shuō)了,那如何實(shí)現(xiàn)和StateMachine一樣的呢?這就需要在 ContinueWith 中新增 ExecuteSynchronously 同步參數(shù),參考如下:

    var query = Task.Run(() => { }).ContinueWith(t =>
    {
    }, TaskContinuationOptions.ExecuteSynchronously);

3. Awaiter

使用Awaiter做任務(wù)延續(xù)的朋友可能相對(duì)少一點(diǎn),它更多的是和 StateMachine 打配合,當(dāng)然單獨(dú)使用也可以,但沒(méi)有前兩者靈活,它更適合那些不帶返回值的任務(wù)延續(xù),本質(zhì)上也是借助 m_continuationObject 字段實(shí)現(xiàn)的一套底層玩法,話不多說(shuō),上一段代碼:


        static Task<string> UseAwaiter()
        {
            var awaiter = Task.Run(() =>
            {
                Thread.Sleep(1000);
                var response = "<html><h1>博客園</h1></html>";
                return response;
            }).GetAwaiter();
            awaiter.OnCompleted(() =>
            {
                var html = awaiter.GetResult();
                Console.WriteLine($"UseAwaiter 的結(jié)果:{html}");
            });
            return Task.FromResult(string.Empty);
        }

前面兩種我配了圖,這里沒(méi)有理由不配了,哈哈,模型圖如下:

接下來(lái)把程序運(yùn)行起來(lái),觀察截圖:


從卦中觀察,它和StateMachine一樣,默認(rèn)都是 一擼到底 的方式。

三:RunContinuations 觀察

這一小節(jié)我們單獨(dú)說(shuō)一下 RunContinuations 方法,因?yàn)檫@里的實(shí)現(xiàn)太精妙了,不幸的是Dnspy和ILSpy反編譯出來(lái)的代碼太狗血,原汁原味的簡(jiǎn)化后代碼如下:

    private void RunContinuations(object continuationObject) // separated out of FinishContinuations to enable it to be inlined
    {
        bool canInlineContinuations =
            (m_stateFlags & (int)TaskCreationOptions.RunContinuationsAsynchronously) == 0 &&
            RuntimeHelpers.TryEnsureSufficientExecutionStack();
        switch (continuationObject)
        {
            // Handle the single IAsyncStateMachineBox case.  This could be handled as part of the ITaskCompletionAction
            // but we want to ensure that inlining is properly handled in the face of schedulers, so its behavior
            // needs to be customized ala raw Actions.  This is also the most important case, as it represents the
            // most common form of continuation, so we check it first.
            case IAsyncStateMachineBox stateMachineBox:
                AwaitTaskContinuation.RunOrScheduleAction(stateMachineBox, canInlineContinuations);
                LogFinishCompletionNotification();
                return;
            // Handle the single Action case.
            case Action action:
                AwaitTaskContinuation.RunOrScheduleAction(action, canInlineContinuations);
                LogFinishCompletionNotification();
                return;
            // Handle the single TaskContinuation case.
            case TaskContinuation tc:
                tc.Run(this, canInlineContinuations);
                LogFinishCompletionNotification();
                return;
            // Handle the single ITaskCompletionAction case.
            case ITaskCompletionAction completionAction:
                RunOrQueueCompletionAction(completionAction, canInlineContinuations);
                LogFinishCompletionNotification();
                return;
        }
    }

卦中的 case 挺有意思的,除了本篇聊過(guò)的 TaskContinuation 和 IAsyncStateMachineBox 之外,還有另外兩種 continuationObject,這里說(shuō)一下 ITaskCompletionAction 是怎么回事,其實(shí)它是 Task.Result 的底層延續(xù)類型,所以大家應(yīng)該能理解為什么 Task.Result 能喚醒,主要是得益于Task.m_continuationObject =completionAction 所致。

說(shuō)了這么說(shuō),如何眼見(jiàn)為實(shí)呢?可以從源碼中尋找答案。


        private bool SpinThenBlockingWait(int millisecondsTimeout, CancellationToken cancellationToken)
        {
            var mres = new SetOnInvokeMres();
            AddCompletionAction(mres, addBeforeOthers: true);
            var returnValue = mres.Wait(Timeout.Infinite, cancellationToken);
        }
        private sealed class SetOnInvokeMres : ManualResetEventSlim, ITaskCompletionAction
        {
            internal SetOnInvokeMres() : base(false, 0) { }
            public void Invoke(Task completingTask) { Set(); }
            public bool InvokeMayRunArbitraryCode => false;
        }

從卦中可以看到,其實(shí)就是把 ITaskCompletionAction 接口的實(shí)現(xiàn)類 SetOnInvokeMres 塞入了 Task.m_continuationObject 中,一旦Task執(zhí)行完畢之后就會(huì)調(diào)用 Invoke() 下的 Set() 來(lái)實(shí)現(xiàn)事件喚醒。

四:總結(jié)

雖然異步任務(wù)延續(xù)有三種實(shí)現(xiàn)方法,但底層都是一個(gè)套路,即借助 Task.m_continuationObject 字段玩出的各種花樣,當(dāng)然他們也是有一些區(qū)別的,即對(duì) m_continuationObject 任務(wù)是否用單獨(dú)的線程調(diào)度,產(chǎn)生了不同的意見(jiàn)分歧。

?轉(zhuǎn)自https://www.cnblogs.com/huangxincheng/p/18662162


該文章在 2025/1/10 8:50:58 編輯過(guò)
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國(guó)內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開(kāi)發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉(cāng)儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購(gòu)管理,倉(cāng)儲(chǔ)管理,倉(cāng)庫(kù)管理,保質(zhì)期管理,貨位管理,庫(kù)位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved