阻塞io(blocking io)
在linux中,預設情況下所有的socket都是blocking,乙個典型的讀操作流程大概是這樣:
當使用者程序呼叫了recvfrom這個系統呼叫,kernel核心就開始了io的第乙個階段:準備資料。對於network io( 網路io )來說,很多時候資料在一開始還沒有到達(比如,還沒有收到乙個完整的udp包),這個時候kernel( 核心 )就要等待足夠的資料到來。
等著對方把資料放到自己作業系統記憶體
而在使用者程序這邊,整個程序會被阻塞。當kernel一直等到資料準備好了,它就會將資料從kernel作業系統快取中拷貝到使用者應用程式記憶體,
然後kernel返回結果,使用者程序才解除block的狀態,重新執行起來。
這就是阻塞io
所以,blocking io的特點就是在io執行的兩個階段(等待資料和拷貝資料兩個階段)都被block了
網路程式設計都是從listen\(\)、send\(\)、recv\(\) 等介面開始的,
使用這些介面可以很方便的構建伺服器/客戶機的模型。然而大部分的socket介面都是阻塞型的。如下圖
ps:所謂阻塞型介面是指系統呼叫(一般是io介面)不返**用結果並讓當前執行緒一直阻塞
只有當該系統呼叫獲得結果或者超時出錯時才返回。
服務端:
from socket import *
server = socket(af_inet,sock_stream)
server.bind(('127.0.0.1',8000))
server.listen(5)
while true:
print("starting...")
conn,addr = server.accept()
print(addr)
w程式設計客棧hile true:
try:
data = conn.recv(1024)
if not data:break
conn.send(data.upper())
except connectionreseterror:
break
server.close()
客戶端from socket import *
client = socket(af_inet,sock_stream)
client.connect(('127.0.0.1',8000))
while true:
msg = input(">>>:").strip()
if not msg:continue
client.send(msg.encode("utf-8"))
data = client.recv(1024)
print(data.decode("utf-8"))
client.close()
實際上,除非特別指定,幾乎所有的io介面 ( 包括socket介面 ) 都是阻塞型的。這給網路程式設計帶來了乙個很大的問題,如在呼叫recv(1024)的同時,執行緒將被阻塞,在此期間,執行緒將無法執行任何運算或響應任何的網路請求。
乙個簡單的解決方案:
在伺服器端使用多執行緒(或多程序)。多執行緒(或多程序)的目的是讓每個連線都擁有獨立的執行緒(或程序),
這樣任何乙個連線的阻塞都不會影響其他的連線。
該方案的問題是 :
開啟多程序或都執行緒的方式,在遇到要同時響應成百上千路的連線請求,則無論多執行緒還是多程序都會嚴重佔據系統資源,
降低系統對外界響應效率,而且執行緒與程序本身也更容易進入假死狀態。
隨著客戶端數量增多,無限制的開執行緒,開銷非常大
不能解決阻塞io問題 ,解決思路:起多執行緒
改進方案:
使用「執行緒池」或「連線池」。「執行緒池」旨在減少建立和銷毀執行緒的頻率,
其維持一定合理數量的執行緒,並讓空閒的執行緒重新承擔新的執行任務。「連線池」維持連線的快取池,盡量重用已有的連線、
減少建立和關閉連線的頻率。這兩種技術都可以很好的降低系統開銷,都被廣泛應用很多大型系統,如websphere、tomcat和各種資料庫等。
改進後方案其實也存在著問題:
「執行緒池」和「連線池」技術也只是在一定程度上緩解了頻繁呼叫io介面帶來的資源占用。而且,所謂「池」始終是有限,
當請求大大超過上限時,「池」構成的系統對外界的響應並不比沒有池的時候效果好多少。所以使用「池」必須考慮其面臨的響應規模,
並根據響應規模調整「池」的大小。
執行緒池應該隨著規模數調大,但是調大執行緒池,要在機器可承受範圍之內。不能把執行緒池無限調大,這樣相當於無限開線程式設計客棧程一樣,
多執行緒還是要用在規模比較小的情況
對應上例中的所面臨的可能同時出現的上千甚至上萬次的客戶jbtkh端請求,「執行緒池」或「連線池」或許可以緩解部分壓力,但是不能解決所有問題。總之,多執行緒模型可以方便高效的解決小規模的服務請求,但面對大規模的服務請求,多執行緒模型也會遇到瓶頸,可以用非阻塞介面來嘗試解決這個問題。
總結:始綜沒有解決單執行緒遇到io問題,單執行緒遇到io,就阻塞,用的是阻塞io模型。
阻塞io模型就是遇到io阻塞不處理,就在原地等著。
應該:監測單執行緒io,遇到io了,這個執行緒不要阻塞。直接切換到另外乙個執行緒執行,這樣單執行緒效率就非常高了。
要解決的問題是:
單執行緒io問題
本文標題: python 併發程式設計 阻塞io模型原理解析
本文位址: /jiaoben/python/268942.html
Python之阻塞IO模型與非阻塞IO模型
python之阻塞io模型與非阻塞io模型 io模型 1 阻塞io 全程阻塞 2 非阻塞io 傳送多次系統呼叫 優點 wait for data時無阻塞 缺點 1 系統呼叫太多 2 資料不是實時接受的 兩個階段 wait for data 非阻塞 copy data 阻塞 3 io多路復用 監聽多個...
併發程式設計 join 阻塞
看看join 阻塞 很多時候,乙個執行緒的輸入可能非常依賴於另外乙個或者多個執行緒的輸出,此時,這個執行緒就需要等待依賴的執行緒執行完畢,才能繼續執行。jdk提供了join 操作來實現這個功能 a依賴b,那麼在a執行緒中去呼叫 b.join a執行緒開始等待b執行緒 無限等待,直到目標執行緒執行完畢...
Python 高階程式設計與非同步IO併發程式設計!
python中一切皆物件 動態語言和靜態語言 1.python中面對物件更徹底,在 python 中 class 魔法函式,包括 和模組都可以是物件,讓動態語言的特性得到充分的體現 2.函式和類也是物件,屬於一等公民 python資源共享群 626017123 def ask name bobby ...