gevent 底層是怎麼實現?app
io模型4個重要概念:異步
兩類socket
#所謂同步,就是在發出一個功能調用時,在沒有獲得結果以前,該調用就不會返回。按照這個定義,其實絕大多數函數都是同步調用。
可是通常而言,咱們在說同步、異步的時候,特指那些須要其餘部件協做或者須要必定時間完成的任務。 #舉例: #1. multiprocessing.Pool下的apply #發起同步調用後,就在原地等着任務結束,根本不考慮任務是在計算仍是在io阻塞,
總之就是一股腦地等任務結束 #2. concurrent.futures.ProcessPoolExecutor().submit(func,).result() #3. concurrent.futures.ThreadPoolExecutor().submit(func,).result()
異步: 提交完任務就無論了,往下執行async
#異步的概念和同步相對。當一個異步功能調用發出後,調用者不能馬上獲得結果。當該異步功能完成後,
經過狀態、通知或回調來通知調用者。若是異步功能用狀態來通知,那麼調用者就須要每隔必定時間檢查一次,效率就很低。
若是是使用通知的方式,效率則很高,由於異步功能幾乎不須要作額外的操做。至於回調函數,其實和通知沒太多區別。 #舉例: #1. multiprocessing.Pool().apply_async() #發起異步調用後,並不會等待任務結束才返回,相反,會當即獲取一個臨時結果(並非最終的結果,多是封裝好的一個對象)。 #2. concurrent.futures.ProcessPoolExecutor(3).submit(func,) #3. concurrent.futures.ThreadPoolExecutor(3).submit(func,)
異步一般和回調機制聯用,提交完任務,任務運行完後,自動觸發,回調函數代碼函數
阻塞:遇到io,阻塞卡主spa
#阻塞調用是指調用結果返回以前,當前線程會被掛起(如遇到io操做)。函數只有在獲得結果以後纔會將阻塞的線程激活。
有人也許會把阻塞調用和同步調用等同起來,實際上他是不一樣的。對於同步調用來講,不少時候當前線程仍是激活的,
只是從邏輯上當前函數沒有返回而已。 #舉例: #1. 同步調用:apply一個累計1億次的任務,該調用會一直等待,直到任務返回結果爲止,
但並未阻塞住(即使是被搶走cpu的執行權限,那也是處於就緒態); #2. 阻塞調用:當socket工做在阻塞模式的時候,accept(),send(),recv()是阻塞io操做,若是沒有數據的狀況下調用recv函數,
則當前線程就會被掛起,直到有數據爲止。
非阻塞:線程
#非阻塞和阻塞的概念相對應,指在不能馬上獲得結果以前也會馬上返回,同時該函數不會阻塞當前線程。
總結:code
#1. 同步與異步針對的是函數/任務的調用方式:同步就是當一個進程發起一個函數(任務)調用的時候,
一直等到函數(任務)完成,而進程繼續處於激活狀態。而異步狀況下是當一個進程發起一個函數(任務)調用的時候,
不會等函數返回,而是繼續往下執行當,函數返回的時候經過狀態、通知、事件等方式通知進程任務完成。
#2. 阻塞與非阻塞針對的是進程或線程:阻塞是當請求不能知足的時候就將進程掛起,而非阻塞則不會阻塞當前進程
io模型5大類:對象
阻塞io模型blog
非阻塞io模型
io多路複用
異步io模型
IO發生時涉及的對象和步驟。對於一個network IO \(這裏咱們以read舉例\),它會涉及到兩個系統對象,一個是調用這個IO的process \(or thread\),另外一個就是系統內核\(kernel\)。當一個read操做發生時,該操做會經歷兩個階段:
1)等待數據準備 (Waiting for the data to be ready) 2)將數據從內核拷貝到進程中(Copying the data from the kernel to the process)