上篇說了線程,進程,cpu,內存,硬盤之間的關系,這篇說下異步和線程
異步
- 因為異步操作無須額外的線程負擔,并且使用回調的方式進行處理,在設計良好的情況下,處理函數可以不必使用共享變量(即使無法完全不用,最起碼可以減少 共享變量的數量),減少了死鎖的可能
- 異步和多線程可以說沒有必然的聯系,只能說異步可以通過多線程實現而已
- 異步IO就是,線程/進程不用阻塞,可以去干其他的事情,等IO完成后,你可以捕獲這個事件,再回頭處理這個已經完成的IO(回頭之前,線程/進程可以去干其他的事情)。
- 常用的異步方式比如異步socket,但是有端口限制問題要注意,請查看我的基于百萬并發的netty nio壓測客戶端
異步IO
考慮到CPU和IO之間巨大的速度差異,一個任務在執行的過程中大部分時間都在等待IO操作,單進程單線程模型會導致別的任務無法并行執行,因此,我們才需要多進程模型或者多線程模型來支持多任務并發執行。
現代操作系統對IO操作已經做了巨大的改進,最大的特點就是支持異步IO。如果充分利用操作系統提供的異步IO支持,就可以用單進程單線程模型來執行多任務,這種全新的模型稱為事件驅動模型,Nginx就是支持異步IO的Web服務器,它在單核CPU上采用單進程模型就可以高效地支持多任務。在多核CPU上,可以運行多個進程(數量與CPU核心數相同),充分利用多核CPU。由于系統總的進程數量十分有限,因此操作系統調度非常高效。用異步IO編程模型來實現多任務是一個主要的趨勢。
對應到Python語言,單進程的異步編程模型稱為協程,有了協程的支持,就可以基于事件驅動編寫高效的多任務程序
同步與異步 & 阻塞與非阻塞
在進行網絡編程時,我們常常見到同步(Sync)/異步(Async),阻塞(Block)/非阻塞(Unblock)四種調用方式,先理解一些概念性的東西。
同步與異步
- 同步與異步同步和異步關注的是消息通信機制 (synchronous communication/ asynchronous communication)所謂同步,就是在發出一個調用時,在沒有得到結果之前,該調用就不返回。但是一旦調用返回,就得到返回值了。換句話說,就是由調用者主動等待這個調用的結果。
而異步則是相反,調用在發出之后,這個調用就直接返回了,所以沒有返回結果。換句話說,當一個異步過程調用發出后,調用者不會立刻得到結果。而是在調用發出后,被調用者通過狀態、通知來通知調用者,或通過回調函數處理這個調用。
典型的異步編程模型比如Node.js。
2016.4.17更新:
POSIX對這兩個術語的定義: - 同步I/O操作:導致請求進程阻塞,直到I/O操作完成
- 異步I/O操作:不導致請求進程阻塞
阻塞與非阻塞
- 阻塞和非阻塞關注的是**程序在等待調用結果(消息,返回值)時的狀態
- 阻塞調用是指調用結果返回之前,當前線程會被掛起。調用線程只有在得到結果之后才會返回。非阻塞調用指在不能立刻得到結果之前,該調用不會阻塞當前線程。
關于阻塞/非阻塞 & 同步/異步更加形象的比喻
老張愛喝茶,廢話不說,煮開水。 出場人物:老張,水壺兩把(普通水壺,簡稱水壺;會響的水壺,簡稱響水壺)。
- 老張把水壺放到火上,立等水開。(同步阻塞)** 老張覺得自己有點傻
- 老張把水壺放到火上,去客廳看電視,時不時去廚房看看水開沒有。(同步非阻塞)** 老張還是覺得自己有點傻,于是變高端了,買了把會響笛的那種水壺。水開之后,能大聲發出嘀~~~~的噪音。
- 老張把響水壺放到火上,立等水開。(異步阻塞)** 老張覺得這樣傻等意義不大
- 老張把響水壺放到火上,去客廳看電視,水壺響之前不再去看它了,響了再去拿壺。(異步非阻塞)** 老張覺得自己聰明了。
所謂同步異步,只是對于水壺而言。普通水壺,同步;響水壺,異步。雖然都能干活,但響水壺可以在自己完工之后,提示老張水開了。這是普通水壺所不能及的。同步只能讓調用者去輪詢自己(情況2中),造成老張效率的低下。
所謂阻塞非阻塞,僅僅對于老張而言。立等的老張,阻塞;看視的老張,非阻塞。情況1和情況3中老張就是阻塞的,媳婦喊他都不知道。雖然3中響水壺是異步的,可對于立等的老張沒有太大的意義。所以一般異步是配合非阻塞使用的,這樣才能發揮異步的效用。
更多參考
1.多進程和多線程
2.Linux下的五種IO模型