.NET非同步程式設計:IO完成埠與BeginRead
【IT168 專稿】寫這個系列原本的想法是討論一下.NET中非同步程式設計風格的變化,特別是F#中的非同步工作流以及未來的.NET 5.0中的基於任務的非同步程式設計模型。但經過前幾篇文章(為什麼需要非同步,傳統的非同步程式設計,使用CPS及yield實現非同步)的發表後,很多人對IO非同步背後實現的原理以及為什麼這樣能提高效能很感興趣。其實我本不想花更多的文字在這些底層實現的細節上,一來我並不擅長這些方面,二來我們使用.NET的非同步IO就不需要關心這些底層東西,因為已經為你封裝完備了。不過為了避免大家一再在這上面商討,我還是在這個系列中間插入了一篇來解釋一下。
本文我將從核心物件IO完成埠開始介紹,然後來瞧瞧.NET BCL中的FileStream.BeginRead是如何利用IO完成埠來實現的。
IO完成埠(IO Completion Port)
大多數人應該或多或少地聽說過IO完成埠這麼個東西,而且也知道它是實現高效能IO,高伸縮性應用的尚方寶劍。IO完成埠是一個非常複雜的核心物件,其實現的也非常巧妙,細細琢磨還是非常有意思的。
建立高伸縮性的應用的一個基本原則就是:建立更少的執行緒。執行緒數更少首先消耗的資源就少,每個執行緒的建立除了要浪費CPU時間外,還要建立一系列的資料結構用來儲存執行緒相關的一些資訊:使用者棧,執行緒上下文,核心棧等。這個總共加起來大概1.5M左右,那麼你算算你的32位機器總共能使用多少記憶體?那麼對應地能建立多少執行緒?可能有人講那對於64位的就無所謂了。嗯,在資源佔用這方面64位確實不用擔心。但是系統中可執行的執行緒數越多,你的CPU數又是有限的(8個?80個?)。Windows的任務排程機制是每個執行緒會執行一個時間片,然後Windows搶佔式的排程另一個執行緒執行。那麼執行緒數越多,Windows勢必要進行更頻繁的執行緒上下文切換。執行緒上下文切換對系統效能的影響在這裡我就不多說了,你可以搜搜資料。
那麼如何做到建立更少的執行緒,而又幹更多的事兒呢?答案就是“不等待”。相對CPU來說,IO裝置的速度簡直低的要命。就好像飛機和拖拉機的差別一樣,我們可不能讓拖拉機拖了飛機的後退兒。而IO完成埠就是為了這個而生的:建立更少的執行緒,幹更多的事兒。
IO完成埠首先不是一個我們看得見摸得著的什麼插口,也和我們常說的80這樣的埠不同。你可以將其理解為一個資料結構或一個物件(下面我會用C#的程式碼來輔助講解IO完成埠,僅僅是講解,這些程式碼並不是真實的實現):
Windows提供了一個CreateIoCompletionPort API來建立IO完成埠,實際上這個API有兩個作用:建立IO完成埠和將一個IO裝置與該埠繫結。建立IO完成埠時有一個很重要的引數:指定同時最多能有多少個執行緒並行執行,這就是為了保證更少的執行緒,如果你將這個數值指定為0,那麼預設值就會是你機器的CPU數。IO埠裡還有一個IO裝置控制程式碼列表,你可以將很多裝置控制程式碼與這個埠繫結(檔案、Socket等):
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->//函式原型
HANDLE CreateIoCompletionPort(
//裝置控制程式碼
HANDLE hFile,
//已有的IO完成埠控制程式碼,如果這裡已經指定,則是將前面指定的裝置與該埠繫結
HANDLE hExistingCompletionPort,
//因為一個IO完成埠可以繫結很多裝置,可以用這個來區分
ULONG_PTR CompletionKey,
//允許同時執行的執行緒數
DWORD dwNumberOfConcurrentThreads
);
//建立一個IO完成埠
HANDLE hIoPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,2);
//建立檔案,如果要非同步訪問檔案則需要指定FILE_FLAG_OVERLAPPED
HANDLE hFile = CreateFile(..);
//將上面建立的檔案控制程式碼與剛才建立的IO完成埠繫結,不僅僅是檔案可以
CreateIoCompletionPort(hFile,hIoPort,1,2);
除此之外,我們還要為該埠建立一些供使用的執行緒。然後讓這些執行緒呼叫Windows提供的GetQueuedCompletionStatus方法。這些執行緒呼叫了該方法後會被放到IO完成埠另外一個資料結構中:一個後進先出的佇列(我們將其稱為等待佇列吧)。然後該執行緒會休眠起來,不佔用CPU。然後我們可以呼叫像ReadFile這樣的方法發起一個IO請求:
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->BOOL ReadFile(
HANDLE hFile,
PVOID pvBuffer,
DWORD nNumBytesToRead,
PDWORD pdwNumBytes,
OVERLAPPED* pOverlapped);
ReadFile(..&overlapped);
相關文章
- IO multiplexing 與 非阻塞網路程式設計程式設計
- [譯] 非同步程式設計:阻塞與非阻塞非同步程式設計
- Windows核心程式設計:第10章 同步裝置IO與非同步裝置IOWindows程式設計非同步
- Java網路程式設計和NIO詳解5:Java 非阻塞 IO 和非同步 IOJava程式設計非同步
- java同步非阻塞IOJava
- 玩轉 PHP 網路程式設計全套阻塞與非阻塞 IOPHP程式設計
- Java 非阻塞 IO 和非同步 IOJava非同步
- python非同步IO程式設計(一)Python非同步程式設計
- 一文徹底搞定(阻塞/非阻塞/同步/非同步)網路IO、併發程式設計模型、非同步程式設計模型的愛恨情仇非同步程式設計模型
- IO模式和IO多路複用(阻塞IO、非阻塞IO、同步IO、非同步IO等概念)模式非同步
- IO模式設定網路程式設計常見問題總結—IO模式設定,阻塞與非阻塞模式程式設計
- 如何解讀 Java IO、NIO 中的同步阻塞與同步非阻塞?Java
- 阻塞IO與非阻塞IO
- .NET之非同步程式設計非同步程式設計
- python 網路程式設計----非阻塞或非同步程式設計Python程式設計非同步
- 初探 Python 3 的非同步 IO 程式設計Python非同步程式設計
- IO - 同步 非同步 阻塞 非阻塞的區別非同步
- Socket程式設計中的同步、非同步、阻塞和非阻塞(轉)程式設計非同步
- 聊聊執行緒與程式 & 阻塞與非阻塞 & 同步與非同步執行緒非同步
- Python併發程式設計之協程/非同步IOPython程式設計非同步
- 非同步程式設計:.NET 4.5 基於任務的非同步程式設計模型(TAP)非同步程式設計模型
- 網路IO之阻塞、非阻塞、同步、非同步總結非同步
- 談談對不同I/O模型的理解 (阻塞/非阻塞IO,同步/非同步IO)模型非同步
- IO通訊模型(二)同步非阻塞模式NIO(NonBlocking IO)模型模式BloC
- [.net 物件導向程式設計進階] (8) 託管與非託管物件程式設計
- 同步與非同步 阻塞與非阻塞非同步
- 程式設計師與非程式設計師的思維差異程式設計師
- suging閒談-netty 的非同步非阻塞IO執行緒與業務執行緒分離Netty非同步執行緒
- 同步非同步 與 阻塞非阻塞非同步
- 同步、非同步、阻塞與非阻塞非同步
- JavaScript非同步程式設計:Generator與AsyncJavaScript非同步程式設計
- 預設非安全埠列表
- IO和socket程式設計程式設計
- 【進階之路】併發程式設計(三)-非阻塞同步機制程式設計
- IO程式設計和NIO程式設計簡介程式設計
- .NET 中的 async/await 非同步程式設計AI非同步程式設計
- Python非同步IO程式設計之-asyncio協程應用例子Python非同步程式設計
- 程式與執行緒、同步與非同步、阻塞與非阻塞、併發與並行執行緒非同步並行