.net異步編程async與await

異步編程的好處:

異步編程並不能提速請求響應,它只能增加程序的吞吐量,最大限度的提升線程的利用率。
討論之前,我們需要了解一個概念:線程池。
線程池微軟官方定義:
線程池線程是後臺線程。 每個線程均使用默認的堆棧大小,以默認的優先級運行,並且位於多線程單元中。 一旦線程池中的線程完成任務,它將返回到等待線程隊列中。 這時開始即可重用它。 通過這種重複使用,應用程序可以避免產生爲每個任務創建新線程的開銷。每個進程只有一個線程池。
翻譯一下就是這個意思:
我們知道一個進程裏面有多個線程,但是一個進程只有一個線程池。線程池負責線程的創建和銷燬。總之就是負責對線程的分配,相當於線程管理員。
下面我會演示一段代碼,使用.net web api 截取的一段代碼:

        public async Task<JsonResult> Get()
        {
            Console.WriteLine("GetString方法開始執行");
            GetString();
            Console.WriteLine("GetString方法繼續執行");
            Console.WriteLine("GetString方法執行結束");
            return new JsonResult(new string[] { "value1", "value2" });
        }

        public async Task<string> GetString()
        {
            Console.WriteLine("AsyncAction方法await之前");
            string result = await Task<string>.Run(() =>
            {
                Thread.Sleep(1000);
                Console.WriteLine("AsyncAction方法sleep一秒後");
                return "AsyncAction的返回值";
            });
            Console.WriteLine("AsyncAction方法await之後-{0}", result);
            return result;
        }

上面的代碼裏面,我沒有在異步方法加上await,輸出的結果如下:在這裏插入圖片描述
我們可以看到程序一直是順序執行,直到在遇到await,線程被掛起,接口返回數據之後,纔在後臺完成了await裏面的操作。
應用場景:
這樣的實現可以讓我們在後臺把一些非常耗時的操作寫在await裏面,而不需要等待他完成的結果,比如說是跟IO有關的操作,接口提前返回數據,讓IO耗時操作,在系統後臺自動運行,而不用關心結果,像發送短信,寫日誌,等等這些操作,都可以用這樣的方式完成

如果我在代碼裏面,調用這個異步方法之前,加上await,那麼輸出的結果又是怎樣呢?大家可以猜一下。我貼一下結果。

        [HttpGet]
        public async Task<JsonResult> Get()
        {
            Console.WriteLine("GetString方法開始執行");
            await GetString();
            Console.WriteLine("GetString方法繼續執行");
            Console.WriteLine("GetString方法執行結束");
            return new JsonResult(new string[] { "value1", "value2" });
        }

        public async Task<string> GetString()
        {
            Console.WriteLine("AsyncAction方法await之前");
            string result = await Task<string>.Run(() =>
            {
                Thread.Sleep(1000);
                Console.WriteLine("AsyncAction方法sleep一秒後");
                return "AsyncAction的返回值";
            });
            Console.WriteLine("AsyncAction方法await之後-{0}", result);
            return result;
        }

在這裏插入圖片描述
我們可以看到這已經是相當於同步操作了,加上await,需要等待await函數的執行結果。

        [HttpGet]
        public async Task<JsonResult> Get()
        {
            Console.WriteLine("線程Id:" + Thread.CurrentThread.ManagedThreadId.ToString("00"));
            Console.WriteLine("GetString方法開始執行");
            await GetString();
            Console.WriteLine("GetString方法繼續執行");
            Console.WriteLine("GetString方法執行結束");
            return new JsonResult(new string[] { "value1", "value2" });
        }

        public async Task<string> GetString()
        {
            Console.WriteLine("AsyncAction方法await之前");
            string result = await Task<string>.Run(() =>
            {
                Console.WriteLine("處理await的線程ID:" + Thread.CurrentThread.ManagedThreadId.ToString("00"));
                Thread.Sleep(1000);
                Console.WriteLine("AsyncAction方法sleep一秒後");
                return "AsyncAction的返回值";
            });
            Console.WriteLine("AsyncAction方法await之後-{0}", result);
            return result;
        }

在這裏插入圖片描述
看着像是創建了新線程,其實是由線程池隨機分配的線程。
總結:
當函數標記爲async的時候,其實是告訴編譯器,函數裏面可能會有await關鍵字,異步的關鍵其實就是這個await,當主線程走到await時,不會新創建一個新線程,去執行await裏面的東西,await操作不會創建新線程,而是標記一個回調,等主線程走完,會把線程放到線程池,然後線程池會分配一個空閒的線程處理await的函數,所以處理await函數的前後線程可能是一個線程,有可能不是一個線程,卻決於線程池的分配。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章