文章出處

返回目錄

應該這樣理解它

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

說一下上面提到的誤解

誤解1:不阻塞主線程

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

誤解2:不阻塞UI

這就更屬于胡扯了,對于一個工作流來說,必須要按著1,2,3的順序去執行,如果是同步代碼,它是一個線程從1執行到3,這個線程將一直被占用!如果是異步代碼,它在執行到1時,線程被回收到池子,其它人可以使用,當1執行完成后,從線程池里取出一個新的線程繼續執行,這叫異步!C#的異步進行友好,使用async,await就可以實現了!

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

        // <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之間

而如果使用同步代碼,結果就完成不一樣了,線程剩余各位可以看下面

線程ID在每個await時是不同的

下面是一個更明顯的測試,依次執行多個await,然后獲取當前線程的ID,它們在異步環境下,有可能是不同的,因為每次都要從池子里拿新的線程!

            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}");

通過這篇文章,我們應該真正理解異步這個概念了吧,記住,異步主要為了提高線程利用率,從而提高系統的吞吐量的,它與并行,主線程阻塞很有直接關系,也不是它所研究的重點,這個大家一定要記住!

返回目錄


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()