python並發編程:阻塞IO

來源:互聯網
上載者:User

標籤:影響   websphere   HERE   except   結果   stream   recv   改進   編程   

阻塞IO(blocking  IO)

在Linux中,預設情況下所有的socket都是blocking,一個典型的讀操作流程大概是這樣:

  當使用者進程調用了recvfrom這個系統調用,kernel就開始了IO的第一個階段:準備資料。對於network io來說,很多時候資料在一開始還沒有到達(比如,還沒有收到一個完整的udp包),這個時候kernel就要等待足夠的資料到來

而在使用者進程這邊,整個進程會被阻塞,當kernel一直等到資料準備好了,它就會將資料從kernel中拷貝到使用者記憶體然後kernel返回結果,使用者進程才解除block的狀態,重新運行起來

  所以,blocking IO的特點就是在IO執行的兩個階段(等待資料和拷貝資料兩個階段)都被block了

幾乎所有的程式員第一次接觸到的網路編程都是從listen(),send(),recv()等介面開始的,使用這些介面可以很方便的構建伺服器/客戶機的模型。然而大部分的socket介面都是阻塞型的。如ps:所謂阻塞型介面是指系統調用(一般是IO介面)不返回調用結果並讓當前線程一直阻塞只有當該系統調用獲得結果或者逾時出錯時才返回。

  

 

實際上,除非特別指定,幾乎所有的IO介面(包括socket介面)都是阻塞型的。這給網路編程帶來了一個很大的問題。如在調用recv(1024)的同時,線程將被阻塞,在此期間,線程將無法執行任何運算或響應任何的網路請求。

一個簡單的解決方案:

在服務端使用多線程(或多進程)。多線程(或多進程)的目的是讓每個串連都擁有獨立的線程(或進程),這樣任何一個串連的阻塞都不會影響其他的串連。

  該方案的問題是:

開啟多進程或多線程的方式,在遇到同時響應成百上千的串連請求,則無論多線程還是多進程都會嚴重佔據系統資源,降低系統對外界響應效率,而且線程與進程本身也更容易進入假死狀態

  改進方案:

很多程式員可能會考慮使用“線程池”或“串連池”。“線程池”旨在減少建立和銷毀線程的頻率,其維持一定合理數量的線程,並讓閒置線程重新承擔新的執行任務。“串連池”維持串連的緩衝池,盡量重用已有的串連,減少建立和關閉串連的頻率。這兩種技術都可以很好的降低系統開銷,都被廣泛應用很多大型系統,如websphere、tomcat和各種資料庫等

  改進後方案其實也存在著問題:

“線程池”和“串連池”技術也只是在一定程度上緩解了頻繁調用IO介面帶來的資源佔用。而且“池”始終尤其上限,當請求大大超過上限時,“池”構成的系統對外界的響應並不比沒有池的時候效果好多少。所以使用“池”必須考慮其面臨的響應規模,並根據規模調整“池”的大小

  對應上例中的所面臨的可能同時出現的上千甚至上萬次的用戶端請求,“線程池”或“串連池”或許可以緩解部分壓力,但是不能解決所有問題。總之,多執行緒模式可以方便高效的解決小規模的服務要求,但面對大規模的服務要求,多執行緒模式也會遇到瓶頸,可以用非阻塞介面來嘗試解決這個問題。

 

練習:

服務端:

from socket import *from threading import Threaddef communicate(conn):    while True:        try:            data = conn.recv(1024)            if not data:                break            conn.send(data.upper())        except ConnectionResetError:            break    conn.close()server = socket(AF_INET, SOCK_STREAM)server.bind((‘127.0.0.1‘, 8080))server.listen(5)while True:    print(‘starting...‘)    conn,addr = server.accept()    print(addr)    t = Thread(target=communicate, args=(conn,))    t.start()server.close()

  用戶端:

from socket import *client = socket(AF_INET, SOCK_STREAM)client.connect((‘127.0.0.1‘, 8080))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()

  

  

python並發編程:阻塞IO

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.