異步與線程阻塞

返回目錄 html

應該這樣理解它

異步,早期開發人員對它有不少誤解,認爲不阻塞主線程就是異步,更有認爲不阻塞UI就是異步,但異步歸根結底和這兩個東西關係並不大,異步的出現主要是爲了提升線程的利用率,讓可用線程更高,而不是一個線程只作一件事,這件事沒有完成就不去作下面的事情,這是不正確的,線程應該被解放出來!事實上,你若是學過nodejs的話,對單線程非阻塞應該更清楚一些,它主要經過方法回調來實現異步的,只是在語法上和C#不太同樣。node

說一下上面提到的誤解

誤解1:不阻塞主線程多線程

若是不阻塞主線程的話,你只能開個新線程完成這個動做,像一些系統通知,它和主線程的工做流程沒有關係,若是開個新線程,與主線程並行執行,這並非咱們說的異步,這只是多線程!它會增長線程的開支,使用不當,會影響系統的吞吐量!異步

誤解2:不阻塞UIasync

這就更屬於胡扯了,對於一個工做流來講,必需要按着1,2,3的順序去執行,若是是同步代碼,它是一個線程從1執行到3,這個線程將一直被佔用!若是是異步代碼,它在執行到1時,線程被回收到池子,其它人可使用,當1執行完成後,從線程池裏取出一個新的線程繼續執行,這叫異步!C#的異步進行友好,使用async,await就能夠實現了!測試

實驗:查看有效的線程剩餘數spa

        // <summary>
        /// 線程非阻塞,線程利用率高
        /// 線程await後能夠去作其它事
        /// 而後await後面方法結束後再申請新線程執行下面的代碼
        /// </summary>
        /// <returns></returns>
        [Route("~/do5")]
        public async Task<string> Do5()
        {
            var sw = new Stopwatch();
            sw.Start();
            await HttpHelper.Get("http://localhost:61699/do1");
            await HttpHelper.Get("http://localhost:61699/do2");
            await HttpHelper.Get("http://localhost:61699/do3");
            await HttpHelper.Get("http://localhost:61699/do4");
            sw.Stop();
            int workerThreads, completionPortThreads;
            ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads);
            return $"max threads:{workerThreads},completionPortThreads:{completionPortThreads},timer:{sw.ElapsedMilliseconds.ToString()}";
        }

咱們來看它的I/O線程剩餘,多刷新幾回,一直維持在32766和32765之間pwa

而若是使用同步代碼,結果就完成不同了,線程剩餘各位能夠看下面線程

線程ID在每一個await時是不一樣的

下面是一個更明顯的測試,依次執行多個await,而後獲取當前線程的ID,它們在異步環境下,有多是不一樣的,由於每次都要從池子裏拿新的線程!code

            await HttpHelper.Get("http://localhost:61699/do1");
            str.Append($"step1:{Thread.CurrentThread.ManagedThreadId}");
            await HttpHelper.Get("http://localhost:61699/do2");
            str.Append($"step2:{Thread.CurrentThread.ManagedThreadId}");
            await HttpHelper.Get("http://localhost:61699/do3");
            str.Append($"step3:{Thread.CurrentThread.ManagedThreadId}");
            await HttpHelper.Get("http://localhost:61699/do4");
            str.Append($"step4:{Thread.CurrentThread.ManagedThreadId}");

經過這篇文章,咱們應該真正理解異步這個概念了吧,記住,異步主要爲了提升線程利用率,從而提升系統的吞吐量的,它與並行,主線程阻塞頗有直接關係,也不是它所研究的重點,這個你們必定要記住!

返回目錄