python 併發程式設計 阻塞IO模型原理解析

2022-10-04 16:27:21 字數 2665 閱讀 8275

阻塞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 ...