python全棧開發day36-IO多路復用
阿新 • • 發佈:2018-06-20
not 多線程 for 3D reset 自適應 pen inpu 建立
一、復習
1、進程、線程、協程
進程:是計算機中最小的資源分配單位,數據隔離,可以利用多核,數據不安全
線程:是計算機中最小的CPU調度單位,數據共享,GIL,數據不安全
協程:是線程的一部分,是由用戶來調度,數據共享,數據安全
2、同步、異步、阻塞、非阻塞
異步:同時做不止一件事
同步:事情一件做完接著下一件
阻塞:recv\recvfrom\accept\sleep\input
非阻塞:
二、IO多路復用
IO操作:
文件處理:文件處理,json.dump/load,input,print,logging
網絡操作:recv/send,resvfrom/sendto,accept/connect
# recv 為什麽要阻塞
# 等待數據來到我Python程序的內存裏
1.阻塞IO:
2.非阻塞IO:
代碼舉例:
# import time import socket sk = socket.socket() sk.bind((‘127.0.0.1‘,9000)) sk.setblocking(False) sk.listen() conn_lst = [] del_lst = []非阻塞IO-serverwhile True: try: conn,addr = sk.accept() #--> 非阻塞,沒有連接來就報錯 conn_lst.append(conn) print(conn) except BlockingIOError: for con in conn_lst: # conn1,conn2,conn3 try: con.send(b‘hello‘) try: print(con.recv(1024)) # 非阻塞 沒有消息來就報錯 except BlockingIOError:pass # recv沒有消息的報錯 except ConnectionResetError: # send沒有連接的報錯 con.close() del_lst.append(con) for con in del_lst: conn_lst.remove(con) del_lst.clear() # 非阻塞的形式實現了並發的socket server # 非阻塞的形式實現了並發的socket server,太耗cpu # 沒有數據來 的時候 程序的高速處理極大地占用了CPU資源
import socket sk = socket.socket() sk.connect((‘127.0.0.1‘,9000)) while True: print(sk.recv(1024)) sk.send(b‘bye‘) sk.close()非阻塞IOclient
3.IO多路復用:
import select import socket sk = socket.socket() sk.bind((‘127.0.0.1‘,9000)) sk.setblocking(False) sk.listen() rlst = [sk] # 監聽的是對象的讀操作 wlst = [] # 監聽的是對象的寫操作 xlst = [] # 監聽的是對象的異常操作 while True: rl,wl,xl = select.select(rlst,wlst,xlst) # [sk,conn] for obj in rl: # [conn1,conn2] if obj == sk: conn,addr = sk.accept() # 每次建立連接的時候conn rlst.append(conn) else: msg = obj.recv(1024) if msg == b‘‘: obj.close() rlst.remove(obj) continue print(msg) obj.send(b‘hello‘) # socketserver # TCP協議的並發操作 selectors + 多線程多路復用IO-select-sever
import socket sk = socket.socket() sk.connect((‘127.0.0.1‘,9000)) while True: sk.send(b‘wahaha‘) print(sk.recv(1024)) sk.close() # IO多路復用的select的工作機制 # select windows 輪詢 # poll linux 輪詢,poll能夠監聽的對象比select要多 # epoll linux 不是采用輪詢的方式,而是采用回調函數的形式多路復用IO-select-client
# IO多路復用的select的工作機制
# select windows 輪詢
# poll linux 輪詢,poll能夠監聽的對象比select要多
# epoll linux 不是采用輪詢的方式,而是采用回調函數的形式
跨平臺或平臺自適應IO多路復用:
import selectors import socket sel = selectors.DefaultSelector() def accept(obj,mask): """ 回調函數,當selectors實例感知有用戶連接服務器時,就會回調該函數。 :param obj: :param mask: :return: """ conn,addr = obj.accept() sel.register(conn, selectors.EVENT_READ, read) # 註冊用戶連接conn到selector監聽列表中 def read(conn,mask): """ 回調函數,當selectors實例感知有用戶發送數據時,就會回調該函數。 :param conn: :param mask: :return: """ try: data = conn.recv(1024) if not data: # 為空則拋出異常由下邊的異常處理語句處理 raise Exception conn.send(data+‘_sb‘.encode(‘utf-8‘)) except Exception as e: print(‘closing‘, conn) sel.unregister(conn) conn.close() sk = socket.socket() sk.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sk.bind((‘127.0.0.1‘, 9000)) sk.listen() sk.setblocking(False) sel.register(sk, selectors.EVENT_READ, accept) while 1: events = sel.select() # [sk,conn1,conn2...] 誰有新的數據就會返回誰 for key, mask in events: callback = key.data # 回到函數 callback(key.fileobj, mask) # 執行回調函數selectors-server
import socket sk = socket.socket() sk.connect((‘127.0.0.1‘,9000)) while 1: inp = input(‘>>>‘) sk.send(inp.encode(‘utf-8‘)) print(sk.recv(1024).decode(‘utf-8‘))selectors-client
4.異步IO:
5.各種IO對比:
python全棧開發day36-IO多路復用