asp.net core 中async/await 使用

asp.net core 中async/await 使用

async/await是用來進行異步調用的形式,內部其實還是采用線程池進行管理。
我們從兩方面來看其運行機制,運行流程和運行線程。

單獨的await

        public async Task<string> call()
        {
            Debug.WriteLine("----------->1");
            int s = await foo();
            Debug.WriteLine("----------->2");
            return "1";
        }
        public async Task<int> foo()
        {
            Debug.WriteLine("----------->3");
            await Task.Delay(500);
            Debug.WriteLine("----------->4");
            return 1;
        }

運行結果:

----------->1
----------->3
----------->4
----------->2

這個很好理解,先主線程運行,然后運行子線程foo()方法,線程等待foo方法運行完畢之后再繼續往下運行。

我們從線程的角度來看一下這里面的線程切換。
Talk is cheap, show me the code

        public async Task<string> Get()
        {
            var info = string.Format("----------->1:{0}", Thread.CurrentThread.ManagedThreadId);
            var infoTask = await TaskCaller();
            var infoTaskFinished = string.Format("----------->2:{0}", Thread.CurrentThread.ManagedThreadId);
            return string.Format("{0},{1},{2}", info, infoTask, infoTaskFinished);
        }

        private async Task<string> TaskCaller()
        {
            await Task.Delay(500);
            return string.Format("----------->3:{0}", Thread.CurrentThread.ManagedThreadId);
        }

結果是

----------->1:1
----------->3:4
----------->2:4

冒號后面的是線程編號,一開始主線程為1,然后進入到子線程4,跳出來之后居然在線程4中執行!很神奇,異步線程接管了接下來的活!

有人就要說了,這個await很同步獲取result一樣啊,看不出有什么異步的優勢在里面,客官莫急,接下來慢慢看。

分開的await

        public async Task<string> call()
        {
            Debug.WriteLine("----------->1");
            Task<int> infoTask = foo();
            Debug.WriteLine("----------->2");
            int s = await infoTask;
            Debug.WriteLine("----------->3");
            return "1";
        }
        public async Task<int> foo()
        {
            Debug.WriteLine("----------->4");
            await Task.Delay(500);
            Debug.WriteLine("----------->5");
            return 1;
        }

定義異步方法foo,然后在call方法中調用,與第一個例子不一樣的是這個例子foo()不立馬使用await,而是運行一段之后再使用await,結果輸出如下:

----------->1
----------->4
----------->2
----------->5
----------->3

看看這個神奇的線程輸出吧。
Talk is cheap, show me the code

        public async Task<string> Get()
        {
            var info = string.Format("----------->1:{0}", Thread.CurrentThread.ManagedThreadId);
            Task<string> task = TaskCaller();
            var infoTaskRunning = string.Format("----------->2:{0}", Thread.CurrentThread.ManagedThreadId);
            var infoTask = await task;
            var infoTaskFinished = string.Format("----------->3:{0}", Thread.CurrentThread.ManagedThreadId);
            return string.Format("{0},{1},{2},{3}", info, infoTask,infoTaskRunning, infoTaskFinished);
        }

        private async Task<string> TaskCaller()
        {
            await Task.Delay(500);
            return string.Format("----------->4:{0}", Thread.CurrentThread.ManagedThreadId);
        }

猜猜結果是什么。

----------->1:1
----------->4:4
----------->2:1
----------->3:4

一開始運行在主線程,后來跳到async方法中執行在線程4中,在沒有使用await時,主線程并沒有停下來,還是按照自己的路往下走,直到async使用了await方法,下面的代碼也是交給了子線程。
至于為什么交給了子線程處理,有一篇文章說是await前后的代碼被分成塊,將await的task交給線程池,線程池執行完畢之后進行moveNext方法,繼續執行await之后的代碼。
有興趣的可以看看這篇文章
async和await刨根問底

當有多個async方法在主程序中被調用

執行的流程就不說了,大家都清楚,主要來看看執行的線程
Talk is cheap, show me the code

        public async Task<string> Get()
        {
            var info = string.Format("----------->1:{0}", Thread.CurrentThread.ManagedThreadId);
            Task<string> task1 = TaskCaller1();
            Task<string> task2 = TaskCaller2();
            var infoTaskRunning = string.Format("----------->2:{0}", Thread.CurrentThread.ManagedThreadId);
            var infoTask1 = await task1;
            var infoTaskFinished1 = string.Format("----------->3:{0}", Thread.CurrentThread.ManagedThreadId);

            var infoTask2 = await task2;
   
            var infoTaskFinished2 = string.Format("----------->4:{0}", Thread.CurrentThread.ManagedThreadId);

            return string.Format("{0},{1},{2},{3},{4},{5}", info, infoTask1, infoTask2,infoTaskRunning, infoTaskFinished1, infoTaskFinished1);
        }

        private async Task<string> TaskCaller1()
        {
            await Task.Delay(500);
            return string.Format("----------->5:{0}", Thread.CurrentThread.ManagedThreadId);
        }

       private async Task<string> TaskCaller2()
        {
            await Task.Delay(500);
            return string.Format("----------->6:{0}", Thread.CurrentThread.ManagedThreadId);
        }

結果如下:

----------->1:4
----------->5:3
----------->6:12
----------->2:4
----------->3:3
----------->4:3

有沒有有個數字很奇怪,對,就是最后的3,前面講過async會接過線程來自己操作下面的代碼,第一個異步方法確實是這樣做了,使得第一個await async之后在線程3上面操作,
而第二個await之后卻還是在線程3上面操作,這不免有些讓人疑惑,還是建議去看上面推薦的async和await刨根問底

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容