為了更好地瞭解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()
Python IO模型
比如,你新買了一臺電腦,我們開機發現,連執行都執行不了,我們買的只是一堆硬體,要想讓電腦執行起來, 靠的就是作業系統,作業系統就是操作軟體的軟體,不僅能操作軟體,還能操控硬體。 核心態,就是留給作業系統專用,而使用者的程序是不可以在,核心裡執行的。 而使用者態就是,我們的程序了,比如360,qq,pyc...
IO模型 IO多路複用
用socket 一定會用到accept recv recvfrom這些方法 正常情況下 accept recv recvfrom都是阻塞的...
Python之阻塞IO模型與非阻塞IO模型
python之阻塞io模型與非阻塞io模型 io模型 1 阻塞io 全程阻塞 2 非阻塞io 傳送多次系統呼叫 優點 wait for data時無阻塞 缺點 1 系統呼叫太多 2 資料不是實時接受的 兩個階段 wait for data 非阻塞 copy data 阻塞 3 io多路複用 監聽多個...