並發編程 - IO模型 - 1.io模型/2.阻塞io/3.非阻塞io/4.多路復用io
阿新 • • 發佈:2018-04-05
post app decode pos win 循環 效率 網絡io als
1.io模型
提交任務得方式:
同步:提交完任務,等結果,執行下一個任務
異步:提交完,接著執行,異步 + 回調 異步不等結果,提交完任務,任務執行完後,會自動觸發回調函數
同步不等於阻塞:
阻塞:遇到io,自己不處理,os會搶走cpu ,解決辦法:監測到io,gevent切換到其他任務,類似欺騙os
非阻塞:cpu 運行
IO分類:
1.阻塞IO blocking IO
2.非阻塞IO nonblocking IO
3.IO多路復用 IO multiplexing
4.信號驅動IO signal driven IO 用得比較少
5.異步IO asynchronous IO
遇到IO: 卡
網絡IO: 原地阻塞
1.server端什麽樣得操作屬於IO行為
# accept recv send 阻塞操作 accept recv 明顯得等 send 不會明顯等,但是一種io行為
2.為什麽IO行為會讓有在原地等待的效果
2.阻塞io
server:
1 from socket import * 2 from threading import Thread 3 4 def communicate(conn): 5 while True: 6 try: 7 data = conn.recv(1024)8 if not data: break 9 conn.send(data.upper()) 10 except ConnectionResetError: 11 break 12 13 conn.close() 14 15 16 17 server = socket(AF_INET, SOCK_STREAM) 18 server.bind((‘127.0.0.1‘,8080)) 19 server.listen(5) 20 21 while True: 22 print(‘starting...‘) 23 conn, addr = server.accept() # io 阻塞 os拿走了cpu 24 print(addr) 25 26 t=Thread(target=communicate,args=(conn,)) 27 t.start() 28 29 server.close()
client:
1 from socket import * 2 3 client=socket(AF_INET,SOCK_STREAM) 4 client.connect((‘127.0.0.1‘,8080)) 5 6 7 while True: 8 msg=input(‘>>: ‘).strip() 9 if not msg:continue 10 client.send(msg.encode(‘utf-8‘)) 11 data=client.recv(1024) 12 print(data.decode(‘utf-8‘)) 13 14 client.close()
3.非阻塞io:
自己監測io 遇到io 就切 並且把 單線程得效率提到最高
導致得問題:
1.當有數據來得時候,cpu 在做其他得事情,不會立即響應
2.服務端沒有任何阻塞,說白了,就是死循環,cpu會一直運轉,線程處於就緒狀態,大量占用cpu ,做無用,這個線程會一直問cpu,有數據沒,有數據沒
不推薦使用
server:
1 from socket import * 2 3 server = socket(AF_INET, SOCK_STREAM) 4 server.bind((‘127.0.0.1‘,8083)) 5 server.listen(5) 6 server.setblocking(False) # 默認True 阻塞 7 print(‘starting...‘) 8 9 10 rlist=[] 11 wlist=[] 12 while True: 13 14 try: # 服務端不停得建鏈接 15 conn, addr = server.accept() 16 rlist.append(conn) 17 print(rlist) 18 except BlockingIOError: # 沒阻塞 19 # print(‘幹其他的活‘) 20 21 #收消息 22 del_rlist = [] 23 for conn in rlist: 24 try: 25 data=conn.recv(1024) 26 if not data: 27 del_rlist.append(conn) 28 continue 29 wlist.append((conn,data.upper())) 30 except BlockingIOError: 31 continue 32 except Exception: 33 conn.close() 34 del_rlist.append(conn) 35 36 #發消息 37 del_wlist=[] 38 for item in wlist: 39 try: 40 conn=item[0] 41 data=item[1] 42 conn.send(data) # send 在數據量 過大時 也會阻塞 43 del_wlist.append(item) 44 except BlockingIOError: 45 pass 46 47 for item in del_wlist: 48 wlist.remove(item) 49 50 for conn in del_rlist: 51 rlist.remove(conn) 52 53 54 server.close()
client:
1 from socket import * 2 3 client=socket(AF_INET,SOCK_STREAM) 4 client.connect((‘127.0.0.1‘,8083)) 5 6 7 while True: 8 msg=input(‘>>: ‘).strip() 9 if not msg:continue 10 client.send(msg.encode(‘utf-8‘)) 11 data=client.recv(1024) 12 print(data.decode(‘utf-8‘)) 13 14 client.close()
4.多路復用io:
wait copy 還多了select 中間有個中介存在,幫問os 有沒有數據
但是如果中介 只有1個 效率不如 阻塞效率
但是如果中介監測多個套接字 ,性能高就是:同時監測多個套接字問os系統好了沒 就比阻塞io效率高
監測套接字得io行為
服務端得套接字有幾類:server conn
select 阻塞io 效率高
比非阻塞io 效率也高 ,一直做無用
總結:
同時監測多個套接字
列表 循環 慢 假設列表數據多,循環 效率低 監測套接字好沒好 從頭到尾 循環1遍
select 列表循環 效率低
poll 可接收得列表數據多 效率也不高
epoll 效率最高得 異步操作 每個套接字身上綁定個回調函數,誰好了誰觸發回調,(就不用去遍歷了 效率低)
epoll windows 不支持
linux 支持
selectors 模塊 自動根據操作系統選擇
poll
epoll
server:
1 from socket import * 2 import select 3 4 server = socket(AF_INET, SOCK_STREAM) 5 server.bind((‘127.0.0.1‘,8083)) 6 server.listen(5) 7 server.setblocking(False) 8 print(‘starting...‘) 9 10 rlist=[server,] 11 wlist=[] 12 wdata={} 13 14 while True: 15 rl,wl,xl=select.select(rlist,wlist,[],0.5) # [] 異常列表 每隔0.5s 問一次 16 print(‘rl‘,rl) 17 print(‘wl‘,wl) 18 19 for sock in rl: 20 if sock == server: 21 conn,addr=sock.accept() 22 rlist.append(conn) 23 else: 24 try: 25 data=sock.recv(1024) 26 if not data: 27 sock.close() 28 rlist.remove(sock) 29 continue 30 wlist.append(sock) 31 wdata[sock]=data.upper() 32 except Exception: 33 sock.close() 34 rlist.remove(sock) 35 36 for sock in wl: 37 data=wdata[sock] 38 sock.send(data) 39 wlist.remove(sock) 40 wdata.pop(sock) 41 42 server.close()
client:
1 from socket import * 2 3 client=socket(AF_INET,SOCK_STREAM) 4 client.connect((‘127.0.0.1‘,8083)) 5 6 7 while True: 8 msg=input(‘>>: ‘).strip() 9 if not msg:continue 10 client.send(msg.encode(‘utf-8‘)) 11 data=client.recv(1024) 12 print(data.decode(‘utf-8‘)) 13 14 client.close()
並發編程 - IO模型 - 1.io模型/2.阻塞io/3.非阻塞io/4.多路復用io