網路程式設計之IO模型

2022-03-23 09:22:58 字數 4771 閱讀 8621

io多路復用概念

io發生時涉及的物件和步驟。對於乙個網路io,它會涉及到兩個系統物件,乙個是呼叫io的程序或者執行緒,另乙個就是系統核心。

如當乙個read操作發生時,會先等待資料準備,然後將資料從核心拷貝到程序中去

阻塞io(blocking io)特點:在執行io的兩個階段(等待資料和拷貝資料兩個階段)都被阻塞了

實際上幾乎所有的io藉口(包括socket埠)都是阻塞型的。如在呼叫recv(1024)的同時,執行緒將被阻塞,在此期間,執行緒將無法執行任何運算或響應任何的網路請求。

解決方案:在服務端使用多執行緒(或者多程序),目的是讓每個連線都擁有獨立的執行緒(或者程序)。但是一旦客戶端同一時間的連線請求過多的話,則會嚴重占用系統資源,降低系統對外界的響應效率。

那麼該如何解決呢?最好的辦法就是使用『執行緒池』或者『連線池』。「執行緒池」旨在減少建立和銷毀執行緒的頻率,其維持一定合理數量的執行緒,並讓空閒的執行緒重新承擔新的執行任務。「連線池」維持連線的快取池,盡量重用已有的連線、減少建立和關閉連線的頻率。這兩種辦法可以很好地降低系統開銷,適用於大型系統。   

上述方案只是一定程度緩解了頻繁呼叫io介面帶來的資源占用,『池』終究是有上限的,當響應規模過大時,必須考慮調整池的大小。

用解決該問題。可以使用非阻塞介面來解決

多執行緒,多程序,程序池,執行緒池都可以實現併發,但是仍然沒有解決io問題,先看一下io非阻塞模型(linux下)

從圖中可以看出,當使用者程序發出read操作時,如果kernel中的資料還沒有準備好,那麼它並不會block使用者程序,而是立刻返回乙個error。從使用者程序角度講 ,它發起乙個read操作後,並不需要等待,而是馬上就得到了乙個結果。使用者程序判斷結果是乙個error時,它就知道資料還沒有準備好,於是使用者就可以在本次到下次再發起read詢問的時間間隔內做其他事情,或者直接再次傳送read操作。一旦kernel中的資料準備好了,並且又再次收到了使用者程序的system call,那麼它馬上就將資料拷貝到了使用者記憶體(這一階段仍然是阻塞的),然後返回。

也就是說非阻塞的recvform系統呼叫呼叫之後,程序並沒有被阻塞,核心馬上返回給程序,如果資料還沒準備好,此時會返回乙個error。程序在返回之後,可以幹點別的事情,然後再發起recvform系統呼叫。重複上面的過程,迴圈往復的進行recvform系統呼叫。這個過程通常被稱之為輪詢。輪詢檢查核心資料,直到資料準備好,再拷貝資料到程序,進行資料處理。需要注意,拷貝資料整個過程,程序仍然是屬於阻塞的狀態。

所以,在非阻塞式io中,使用者程序其實是需要不斷的主動詢問kernel資料準備好了沒有。

相關引數

server.setblocking() #

預設是true

server.setblocking(false)

#false的話就成非阻塞了,這只是對於socket套接字來說的

#所以,在非阻塞式io中,使用者程序其實是需要不斷的主動詢問核心資料準備好了沒有。

wait data

#等資料,這個階段是不阻塞的

copy data

#這個階段還是要阻塞的

server端

import socket

sk = socket.socket()

sk.bind(('127.0.0.1',9000))

sk.setblocking(false)

sk.listen()

conn_lst =

del_lst =

while true:

try:

conn,addr = sk.accept() # 非阻塞的模型

print(conn,addr)

except blockingioerror as e:

for conn in conn_lst: #[conn1,conn2,conn3]

try:

msg= conn.recv(1024) # 非阻塞

if not msg: # 判定是否為空

conn.close()

continue

print(msg)

msg = msg.decode('utf-8').upper()

conn.send(msg.encode('utf-8'))

except blockingioerror:pass # 阻塞io報錯,直接pass

for conn in del_lst:

conn_lst.remove(conn)

del_lst.clear()

client端

import time

import socket

sk = socket.socket()

sk.connect(('127.0.0.1',9000))

print(sk)

for i in range(20):

sk.send(b'hello')

print(sk.recv(1024))

time.sleep(1)

sk.close()

非阻塞io模型優點

能夠在等待任務完成的時間裡幹其他活了(包括提交其他任務,也就是 「後台」 可以有多個任務在「」同時「」執行)。

非阻塞io模型缺點:

1. 迴圈呼叫recv()將大幅度推高cpu佔用率

2. 任務完成的響應延遲增大了,因為每過一段時間才去輪詢一次read操作,而任務可能在兩次輪詢之間的任意時間完成。這會導致整體資料吞吐量的降低。

當使用者程序呼叫了select,那麼整個程序會被block,而同時,kernel會「監視」所有select負責的socket,當任何乙個socket中的資料準備好了,select就會返回。這個時候使用者程序再呼叫read操作,將資料從kernel拷貝到使用者程序。

作業系統中的io多路復用的機制select:

windows作業系統提供給你的一種監聽接收資料io的乙個**

select模組:

python使用作業系統select機制的功能

server端:

import socket

import select

sk = socket.socket()

sk.bind(('127.0.0.1',9000))

sk.setblocking(false)

sk.listen()

l = [sk] # sk.accept

while true:

r,w,x = select.select(l,,) # 阻塞

for obj in r:

if obj is sk:

conn,addr = obj.accept()

else:

msg = obj.recv(1024)

if not msg:

obj.close()

l.remove(obj)

continue

print(msg)

obj.send(b'bye')

client端:

import socket

sk = socket.socket()

sk.connect(('127.0.0.1',9000))

while true:

sk.send(b'hello')

print(sk.recv(1024))

sk.close()

該模型優點:

相比其他模型,使用select() 的事件驅動模型只用單執行緒(程序)執行,占用資源少,不消耗太多 cpu,同時能夠為多客戶端提供服務。如果試圖建立乙個簡單的事件驅動的伺服器程式,這個模型有一定的參考價值。

該模型缺點:

首先select()介面並不是實現「事件驅動」的最好選擇。因為當需要探測的控制代碼值較大時,select()介面本身需要消耗大量時間去輪詢各個控制代碼。

對於io多路復用(select)

select檢測的是哪個套接字準備好了(檢測的時候等待了,變成阻塞了)

select之所以比阻塞io好,就是因為select可以檢測多個套接字

多個鏈結下select才能發揮它的優勢

但是你的套接字特別多,你怎麼知道哪個好了呢,那麼就得用迴圈去遍歷一下

那麼如果特別多的時候,效率也就不咋高了

epoll:只支援linux系統(就是為了解決select效率低的問題)

epoll比pool,select效率高

selectors 更好用,解決了上面select,epoll,pool的問題

socketserver用這個模組io問題也解決了,實現併發也解決了(見鏈結文章最底部例項

網路程式設計之 IO模型

我們這裡研究的io模型都是針對網路io的 blocking io 阻塞io nonblocking io 非阻塞io io multiplexing io多路復用 signal driven io 訊號驅動io asynchronous io 非同步io 由signal driven io 訊號驅動...

網路程式設計之IO模型 非同步IO

linux下的asynchronous io其實用得不多,從核心2.6版本才開始引入。先看一下它的流程 使用者程序發起read操作之後,立刻就可以開始去做其它的事。而另一方面,從kernel的角度,當它受到乙個asynchronous read之後,首先它會立刻返回,所以不會對使用者程序產生任何bl...

Linux網路程式設計之IO模型

同步是指乙個任務的完成需要依賴另外乙個任務時,只有等待被依賴的任務完成後,依賴的任務才能算完成。非同步是指不需要等待被依賴的任務完成,只是通知被依賴的任務要完成什麼工作,依賴的任務也立即執行,只要自己完成了整個任務就算完成了,非同步一般使用狀態 通知和 阻塞是指呼叫結果返回之前,當前執行緒會被掛起,...