NIO與IO多執行緒相比,為什麼使用NIO?

2022-09-10 04:48:09 字數 2210 閱讀 6289

傳統的socket io中,server一直監聽服務埠,當乙個請求連線傳送到server端時,server端獲取當前的socket,然後為socket分配乙個執行緒(通過new方式或者執行緒池獲取乙個可用的執行緒),讓該執行緒獨佔這個socket,執行相關任務、直到任務執行完成後,釋放socket和任務執行緒,相當於乙個執行緒為乙個socket服務,直到這個socket生命週期結束;當併發的連線數量非常巨大且是長連線(socket長連線,不釋放)時,由於socket長時間占用執行緒,執行緒池無法有效**,也會保留大量任務執行緒,導致所占用的棧記憶體和cpu執行緒切換的開銷將非常巨大。

使用nio reactor模型時,server也需要乙個獨立的執行緒監聽服務埠,當乙個請求連線傳送到server端時,server端也會獲取到當前連線的socket;但server不會立即將其分配乙個任務執行緒,而是用乙個channel(可以理解為記憶體中的乙個物件)和socket繫結,並註冊感興趣的事件標籤(讀、寫等),由底層硬體監聽相關事件訊息(具體實現原理不在此詳細說明);例如當該socket對應的讀緩衝區有資料時,server就會收到可讀事件(之前channel註冊事件標籤),此時server會為socket分配乙個任務執行緒(通過new方式或者執行緒池獲取乙個可用的執行緒),任務執行緒能夠直接獲取到快取區的資料並根據業務進行處理,當任務執行完成(socket快取區的資料都處理完畢,當前無可讀資料),任務執行緒被執行緒池**,若當前socket還未斷開(長連線,乙個socket連線可能會下發多個任務,比如乙個連線序列下發多個http請求,任務中間有時間間隔),可通過channel重新註冊相關事件標籤。通過上述描述可知,nio採用io多路復用方式,不再需要為每個socket連線建立單獨的執行緒,可以用乙個含有限數量執行緒的執行緒池,甚至乙個執行緒來為任意數量的連線服務,當任務執行完成可及時**,用於下乙個已就緒的socket連線。達到執行緒數量小於連線數量的效果,有效解決了傳統多執行緒io的問題;在此說明一下,若socket的快取區只包含一部分資料(還有資料在傳輸中,比如乙個http請求中body資料過大,分多個tcp包傳輸),此時任務執行緒只能處理當前資料,然後阻塞等待剩餘資料(通過wait方式不會占用cpu時間),直到任務完整執行完成。

下面用乙個例子,形象說明一下上述流程(例子**

小量的執行緒如何同時為大量連線服務呢,答案就是就緒選擇。這就好比到餐廳吃飯,每來一桌客人,都有乙個服務員專門為你服務,從你到餐廳到結帳走人,這樣方式的好處是服務***,一對一的服務vip,可是缺點也很明顯,成本高,如果餐廳生意好,同時來100桌客人,就需要100個服務員,那老闆發工資的時候得心痛死了,這就是傳統的乙個連線乙個執行緒的方式。

老闆很聰明。這老闆就開始捉摸怎麼能用10個服務員同時為100桌客人服務呢,老闆就發現,服務員在為客人服務的過程中並不是一直都忙著,客人點完菜,上完菜,吃著的這段時間,服務員就閒下來了,可是這個服務員還是被這桌客人占用著,不能為別的客人服務,就是工作不飽滿。那怎麼把這段閒著的時間利用起來呢。這餐廳老闆就想了乙個辦法,讓乙個服務員(前台)專門負責收集客人的需求,登記下來,比如有客人進來了、客人點菜了,客人要結帳了,都先記錄下來按順序排好。每個服務員到這裡領乙個需求,比如點菜,就拿著選單幫客人點菜去了。點好菜以後,服務員馬上回來,領取下乙個需求,繼續為別人客人服務去了。這種方式服務質量就不如一對一的服務了,當客人資料很多的時候可能需要等待。但好處也很明顯,由於在客人正吃飯著的時候服務員不用閒著了,服務員這個時間內可以為其他客人服務了,原來10個服務員最多同時為10桌客人服務,現在可能為50桌,60客人服務了。

這種服務方式跟傳統的區別有兩個:

1、增加了乙個角色,要有乙個專門負責收集客人需求的人。nio裡對應的就是selector。

2、由阻塞服務方式改為非阻塞服務了,客人吃著的時候服務員不用一直侯在客人旁邊了。傳統的io操作,比如read(),當沒有資料可讀的時候,執行緒一直阻塞被占用,直到資料到來。nio中沒有資料可讀時,read()會立即返回0,執行緒不會阻塞。

nio中,客戶端建立乙個連線後,先要將連線註冊到selector,相當於客人進入餐廳後,告訴前台你要用餐,前台會告訴你你的桌號是幾號,然後你就可能到那張桌子坐下了,selectionkey就是桌號。當某一桌需要服務時,前台就記錄哪一桌需要什麼服務,比如1號桌要點菜,2號桌要結帳,服務員從前台取一條記錄,根據記錄提供服務,完了再來取下一條。這樣服務的時間就被最有效的利用起來了。

tips

通過上面的舉例,是不是感覺nio完勝阻塞io呢?其實上面的例子也說明了,傳統阻塞io屬於vip服務,如果客戶比較重要(非常重要、付費的服務連線),可使用傳統阻塞io獨佔執行緒,為客戶提供優質服務。

為什麼使用多執行緒

1 耗時的操作使用執行緒,提高應用程式響應 2 並行操作時使用執行緒,如c s架構的伺服器端併發執行緒響應使用者的請求。3 多cpu系統中,使用執行緒提高cpu利用率 4 改善程式結構。乙個既長又複雜的程序可以考慮分為多個執行緒,成為幾個獨立或半獨 立的執行部分,這樣的程式會利於理解和修改。使用多執...

為什麼要使用多執行緒

一 多執行緒的一些解釋 來至知乎 我覺得解釋的比較好,比較詳細,就給大家分享一下 1 單程序單執行緒 乙個人在一張桌子上吃菜 2 單程序多執行緒 多個人在同一張桌子上吃菜 3 多程序單執行緒 多個人每個人在自己的桌子上吃菜 多執行緒的問題就是多個人在同一張桌子上吃同一道菜時會發生爭搶,如果兩個人同時...

為什麼使用多執行緒 非同步操作

c 是一門支援多執行緒的語言,因此執行緒的使用也是比較常見的。由於執行緒的知識在win32程式設計的時候已經說得過多,所以在.net中很少介紹這部分 可能.net不覺得這部分是它所特有的 那麼執行緒相關的問題大致有如下四類 這篇文章只討論單執行緒 單執行緒與 ui執行緒這兩方面的問題 問題一,執行緒...