首先討論下使用事件驅動,非同步程式設計的優點:
充分利用了系統資源,執行**無須阻塞等待某種操作完成,有限的資源可以用於其他的任務。其非常適合於後端的網路服務程式設計。
在伺服器開發中,併發的請求處理是個大問題,阻塞式的函式會導致資源浪費和時間延遲。通過事件註冊、非同步函式,開發人員可以提高資源的利用率,效能也會改善。其nginx和node.js處理併發都是採用的事件驅動非同步非阻塞模式。其中nginx中處理併發用的是epoll,poll,queue等方式,node.js使用的是libev,它們對大規模的http請求處理的都很好。
阻塞《node.js開發指南》是這樣定義的:執行緒在執行中如果遇到(i/o 操作)如磁碟讀寫或網路通訊,通常要耗費較長的時間,這時作業系統會剝奪這個執行緒的 cpu 控制權,使其暫停執行,同時將資源讓給其他的工作執行緒,這種執行緒排程方式稱為 阻塞。當 i/o 操作完畢時,作業系統將這個執行緒的阻塞狀態解除,恢復其對cpu的控制權,令其繼續執行。這種 i/o 模式就是通常的同步式 i/o(synchronous i/o)或阻塞式 i/o(blocking i/o)。
阻塞呼叫是指呼叫結果返回之前,當前執行緒會被掛起。函式只有在得到結果之後才會返回。有人也許會把阻塞呼叫和同步呼叫等同起來,實際上它們是不同的。對於同步呼叫來說,很多時候當前執行緒還是啟用的,只是從邏輯上當前函式沒有返回而已。例如,我們在csocket中呼叫receive函式,如果緩衝區中沒有資料,這個函式就會一直等待,直到有資料才返回。而此時,當前執行緒還會繼續處理各種各樣的訊息。如果主視窗和呼叫函式在同乙個執行緒中,除非你在特殊的介面操作函式中呼叫,其實主介面還是應該可以重新整理。socket接收資料的另外乙個函式recv則是乙個阻塞呼叫的例子。當socket工作在阻塞模式的時候, 如果沒有資料的情況下呼叫該函式,則當前執行緒就會被掛起,直到有資料為止。
非阻塞非阻塞是這樣定義的,當執行緒遇到 i/o 操作時,不會以阻塞的方式等待 i/o 操作的完成或資料的返回,而只是將 i/o 請求傳送給作業系統,繼續執行下一條語句。當作業系統完成 i/o 操作時,以事件的形式通知執行 i/o 操作的執行緒,執行緒會在特定時候處理這個事件。
對比阻塞與非阻塞
阻塞模式下,乙個執行緒只能處理一項任務,要想提高吞吐量必須通過多執行緒。
非阻塞模式下,乙個執行緒永遠在執行計算操作,這個執行緒所使用的 cpu 核心利用率永遠是 100%,i/o 以事件的方式通知。
在阻塞模式下,多執行緒往往能提高系統吞吐量,因為乙個執行緒阻塞時還有其他執行緒在工作,多執行緒可以讓 cpu 資源不被阻塞中的執行緒浪費。
而在非阻塞模式下,執行緒不會被 i/o 阻塞,永遠在利用 cpu。多執行緒帶來的好處僅僅是在多核 cpu 的情況下利用更多的核。
來看看《深入淺出node.js》對非同步i/o的解釋,在作業系統中,程式執行的空間分為核心空間和使用者空間。我們常常提起的非同步i/o,其實質是使用者空間中的程式不用依賴核心空間中的i/o操作實際完成,即可進行後續任務。
i/o的阻塞與非阻塞的解釋
阻塞模式的i/o會造成應用程式等待,直到i/o完成。同時作業系統也支援將i/o操作設定為非阻塞模式,這時應用程式的呼叫將可能在沒有拿到真正資料時就立即返回了,為此應用程式需要多次呼叫才能確認i/o操作完全完成。
i/o的同步與非同步i/o的同步與非同步出現在應用程式中。如果做阻塞i/o呼叫,應用程式等待呼叫的完成的過程就是一種同步狀況。相反,i/o為非阻塞模式時,應用程式則是非同步的。
參照《node.js入門經典》中對同步的解釋,同步的**意味著每一次執行乙個操作,在乙個操作完成之前,**的執行會被阻塞,無法移到下乙個操作上。也就是說**的執行會在函式返回前停止。直到函式返回後,**才會繼續執行。
相反,非同步就意味著函式的執行無需等待某個操作的結果就可以繼續執行,其操作的結果會在事件發生時由**來處理。
非同步i/o優缺點
使用同步io,它的優點是可以使程式除錯方便,但是它的缺點也是明顯的,程式的執行過程中如果入到一些耗時的io操作,程式的執行都要等待該io的完成,在這個等待的過程中,程式無法充分利用cpu,導致了cpu的閒置,為了充分利用cpu,和io並行操作,常用的方法有2中:
(1)多執行緒單程序
多執行緒的設計之處就是為了在共享的程式空間中,實現並行處理任務,從而達到充分利用cpu的效果。
多執行緒缺點:
其一、執行時(執行緒切換)上下文交換的開銷較大,乙個執行緒大約需要2m的記憶體空間,占用資源較大。
其二、狀態同步(鎖)的問題,它也使得程式的編寫和呼叫複雜化。
(2)單執行緒多程序
為了避免多執行緒造成的使用不便問題,有的語言選擇了單執行緒保持呼叫簡單化,採用啟動多程序的方式來達到充分利用cpu和提公升總體的並行處理能力。它的缺點在於業務邏輯複雜時(涉及多個i/o呼叫),因為業務邏輯不能分布到多個程序之間,事務處理時長要遠遠大於多執行緒模式。
非同步i/o與輪詢技術
當進行非阻塞i/o呼叫時,要讀到完整的資料,應用程式需要進行多次輪詢,才能確保讀取資料完成,以進行下一步的操作。輪詢技術的缺點在於應用程式要主動呼叫,會造成占用較多cpu時間片,效能較為低下。現存的輪詢技術有以下這些: read、select、poll、epoll、pselect、kqueue
read是效能最低的一種,它通過重複呼叫來檢查i/o的狀態來完成完整資料讀取。
select是一種改進方案,通過對檔案描述符上的事件狀態來進行判斷。
作業系統還提供了poll、epoll等多路復用技術來提高效能。
輪詢技術滿足了非同步i/o確保獲取完整資料的保證。但是對於應用程式而言,它仍然只能算時一種同步,因為應用程式仍然需要主動去判斷i/o的狀態,依舊花費了很多cpu時間來等待。上一種方法重複呼叫read進行輪詢直到最終成功,使用者程式會占用較多cpu,效能較為低下。而實際上作業系統提供了select方法來代替這種重複read輪詢進行狀態判斷。select內部通過檢查檔案描述符上的事件狀態來進行判斷資料是否完全讀取。但是對於應用程式而言它仍然只能算是一種同步,因為應用程式仍然需要主動去判斷i/o的狀態,依舊花費了很多cpu時間等待,select也是一種輪詢。
理想的非同步i/o模型
理想的非同步i/o應該是應用程式發起非同步呼叫,而不需要進行輪詢,進而處理下乙個任務,只需在i/o完成後通過訊號或是**將資料傳遞給應用程式即可。
暫時就整理這麼多吧,感覺好多看過的東西都忘記了,回頭會寫一篇關於epoll使用的詳細例子,該例子支援2w併發是通過的。哎,今天狀態不好,寫的不好,本打算自己多加點什麼的,結果都是參考別人的,如有錯誤請大家指正,謝謝。
非同步非阻塞
sk.setblocking false 不會阻塞但是會報錯 setattr sk,callback func url func 1 try 阻塞,非阻塞報錯,捕捉錯誤 sk.connect url func 0 80 except blockingioerror as e pass while t...
阻塞,非阻塞,非同步,同步
之前一直對這個概念理不太清楚,今天看到一篇文章感覺不錯 本文 老張愛喝茶,廢話不說,煮開水。出場人物 老張,水壺兩把 普通 水壺,簡稱水壺 會響的水壺,簡稱響水壺 1 老張把水壺放到火上,立等水開。同步阻塞 老張覺得自己有點傻 2 老張把水壺放到火上,去客廳看電視,時不時去廚房看看水開沒有。同步非阻...
同步 非同步 阻塞 非阻塞
故事 老王燒開水。出場人物 老張,水壺兩把 普通水壺,簡稱水壺 會響的水壺,簡稱響水壺 老王想了想,有好幾種等待方式 1.老王用水壺煮水,並且站在那裡,不管水開沒開,每隔一定時間看看水開了沒。同步阻塞 老王想了想,這種方法不夠聰明。2.老王還是用水壺煮水,不再傻傻的站在那裡看水開,跑去寢室上網,但是...