後執行緒時代 的 應用程式 架構
“後執行緒時代”, 這跟 好幾個 名詞 有關係, C# async await 關鍵字, Socket Async, ThreadPool, 單體(Monosome), “非同步回撥流” 。
“非同步回撥流” 是 “非同步回撥流派” 的 意思, node.js, libuv, Java Netty , 這些 是 典型的 非同步回撥流 。
async await 是 單體(Monosome),
我在之前的 文章 《我 反對 使用 async await》
至於 Socket Async , 和 async await 有關係, 也跟 非同步回撥流 有關係 。
我們來看看 一位網友 從 一篇文章 上 節取 下來的 2 段文字 :
所以, 從 理論 上看, 過多的 執行緒切換 對 效能 的 消耗 是 挺大的, 如果能 省去 這部分 開銷, “節省” 下來的 效能 是 可觀 的, 也許能讓 伺服器 的 吞吐量(併發量) 提高 1 個 數量級 。
所以, Visual Studio 自己也在使用 async await, 從 Visual Studio 有時候 報錯 的 錯誤資訊 來看, 錯誤資訊 中含有 “MoveNext_xx ……” 這樣的文字, 這就是 async await 。
執行緒池(ThreadPool) 本身 就能 將 執行緒數量 控制在一個 有限 的 範圍內 ,
而 將 執行緒數量 控制在一個 有限 的 範圍內 是 減少 執行緒切換 的 基礎 。
我 猜測 async await 的 底層 是 基於 ThreadPool 的, 是以 ThreadPool 作基礎的 。
如果是這樣, 那麼 async await 和 非同步回撥流 是 等價 的 。
什麼是 非同步回撥流 ?
我們可以把 程式 分為 3 個部分 :
1 順序執行
2 等待 IO
3 定時輪詢
1 把 順序執行 的 多工 放到 ThreadPool 的 工作佇列 裡 排隊, 讓 ThreadPool 排程執行,
2 對於 IO 呼叫, 採用 非同步呼叫 的 方式, 傳入 回撥委託, 當 IO 完成時, 當 IO 完成時, 回撥委託,
3 對於 定時輪詢, 採用 ThreadPool 提供的方式, 如 Timer,
這樣, 做到以上 3 點, 就是 純粹 的 非同步回撥流 。
理論上, 非同步回撥 流 可以將 執行緒數量 控制在 有限 的 範圍內, 或者, 只需要 使用 很小數量 的 執行緒 。
這樣, 就像上面說的, 可以節省“可觀”的 效能, 可能能讓 伺服器 的 吞吐量 提高 1 個 數量級 。
從 實驗 中, 我們看到, 在 併發量 大 時, 比如 800 個 Socket 連線 以上時, ThreadPool 的 效能 優於 NewThread 的方式, NewThread 是指 為 每個連線 建立一個 執行緒 。
但是, 如果 Server 端 Socket 的 操作 全部使用 非同步 的 方式, 是否 會比 同步的 Receive() Send() 方式 的 效能 更高, 這個 沒有 看到 有說服力 的 實驗 。
So ……
So …… ?
So ?