為了更好地了解io模型,我們需要事先回顧下:同步、非同步、阻塞、非阻塞1.網路傳輸中的兩個階段 分別是 waitdata 和 copydata
send---copydata
recv---waitdata + copydata
記住這兩點很重要,因為這些io模型的區別就是在兩個階段上各有不同的情況。
2.阻塞io
無論是執行緒 程序 還是執行緒 程序池 統統都是阻塞io
應用程式 傳送 系統呼叫---作業系統等待資料(wait)---資料準備好 return data
所以,blocking io的特點就是在io執行的兩個階段(等待資料和拷貝資料兩個階段)都被block了。
3.非阻塞io
協程是一種非阻塞io
server.setblocking(false)將阻塞修改為非阻塞
最直接體現 recv send accept 都不會阻塞 會立即執行
但是不能保證立馬就有資料 沒有資料丟擲異常
我們需要手動捕獲異常 捕獲異常後可以處理別的任務
可以實現單執行緒併發的效果 但會大量占用cpu資源
while true:
pass
所以,在非阻塞式io中,使用者程序其實是需要不斷的主動詢問kernel資料準備好了沒有。
4.多路復用
管理連線的一種方式
為什麼使用它? 相對於非阻塞io降低無用的系統呼叫
怎麼管?
核心函式select 幫你檢測所有的連線 找出可以被處理(可以讀寫)的連線
(預設時阻塞的 阻塞到有任意乙個連線可以被處理)
結論: select的優勢在於可以處理多個連線,不適用於單個連線
一 建立連線 和管理連線
1.建立伺服器socket物件
2.將伺服器物件交給select來管理
3.一旦有客戶端發起連線 select將不在阻塞
4.select將返回乙個可讀的socket物件(第一次只有伺服器)
5.伺服器的可讀代表有連線請求 需要執行accept 返回乙個客戶端連線conn 由於是非阻塞 不能立即去recv
6.把客戶端socket物件也交給select來管理 將conn加入兩個被檢測的列表中
7.下一次檢測到可讀的socket 可能是伺服器 也可能客戶端 所以加上判斷 伺服器就accept 客戶端就recv
8.如果檢測到有可寫(可以send就是系統快取可用)的socket物件 則說明可以向客戶端傳送資料了
7 和 8 執行順序不是固定的
二 處理資料收發
兩個需要捕獲異常的地方
1.recv 執行第7步 表示可以讀 為什麼異常 只有一種可能客戶端斷開連線
還需要加上if not 判斷是否有資料 ;linux下 對方下線不會丟擲異常 會收到空訊息
2.send 執行第8步 表示可以寫 為什麼異常 只有一種可能客戶端斷開連線)
強調:1. 如果處理的連線數不是很高的話,使用select/epoll的web server不一定比
使用multi-threading + blocking io的web server效能更好,可能延遲還更大。
select/epoll的優勢並不是對於單個連線能處理得更快,而是在於能處理更多的連線。
2. 在多路復用模型中,對於每乙個socket,一般都設定成為non-blocking,但是,如上圖所示,
整個使用者的process其實是一直被block的。只不過process是被select這個函式block,而不是被socket io給block。
結論: select的優勢在於可以處理多個連線,不適用於單個連線
5.非同步io 網路io+本地io 都適用
io包括 網路io 本地io
上面的三種io模型描述的都是網路io,不是本地io的問題
解決的方案就是:
將同步的io操作改成非同步的io操作 在io期間 可以執行其他的任務
最終的解決方案就是協程 使用asyncio模組 該模快實現非同步io 內部使用協程實現
它的流程:
使用者程序發起read操作之後,立刻就可以開始去做其它的事。而另一方面,從kernel的角度,
當它受到乙個asynchronous read之後,首先它會立刻返回,所以不會對使用者程序產生任何block。
然後,kernel會等待資料準備完成,然後將資料拷貝到使用者記憶體,
當這一切都完成之後,kernel會給使用者程序傳送乙個signal,告訴它read操作完成了。
socketserver
是什麼? 對伺服器端的socket的封裝
封裝了多執行緒 多程序 io模型,支撐高併發 高併發 的socket套接字
為什麼用? 簡化**
使用方法:
socketserver (forkingudp forkingtcp windows無法使用)
核心類 threadingudpserver threadingtcpserver
threadingtcpserver 例項化時 傳入伺服器位址 和 自定義的乙個資料處理類
自定義類需要繼承baserequesthandler類中需包含handle函式
物件呼叫serve_forever
tcp服務端
import socketserver
class myhandler(socketserver.baserequesthandler):
def handler(self):
while true:
try:
data=self.request.recv(1024)
if not data:break
print(data.decode('utf-8'))
self.request.send(data.upper())
except connectionreseterror:
break
self.request.close()
if __name__ == '__main__':
server=socketserver.threadingtcpserver(('127.0.0.1',8080),myhandler)
server.serve_forever()
udp服務端
import socketserver
class myhandler(socketserver.baserequesthandler):
def handle(self):
data,server=self.request
print(data.decode('utf-8'))
server.sendto(data.upper(),self.client_address)
if __name__ == '__main__':
server=socketserver.threadingudpserver(('127.0.0.1',8080),myhandler)
server.serve_forever()
網路IO模型
io有兩種操作,同步io和非同步io。同步io指的是,必須等待io操作完成後,控制權才返回給使用者程序。非同步io指的是,無須等待io操作完成,就將控制權返回給使用者程序。網路中的io,由於不同的io裝置有著不同的特點,網路通訊中往往需要等待。常見的有以下4種情況。1 輸入操作 等待資料到達套接字接...
網路IO模型
一 阻塞io模型 阻塞io基於socket程式 原理 recv接收資料時,不是直接接收資料,而是程式將系統呼叫的命令傳送到作業系統 當作業系統收到接收資料的請求,若此時無資料,作業系統會繼續等待,處於等待資料階段 wait for data階段 這個階段相對漫長 當資料來了,作業系統會拷貝資料 co...
網路I O模型 5種常見的網路I O模型
阻塞與非阻塞 阻塞就是卡在那兒什麼也不做,雙方之間也沒有資訊溝通。非阻塞就是即使對方不能馬上完成請求,雙方之間也有資訊的溝通。同步與非同步 同步就是一件事件只由乙個過程處理完成,不論阻塞與非阻塞,最後完成這個事情的都是同乙個過程 非同步就是一件事由兩個過程完成,前面乙個過程通知,後面乙個過程接受返回...