標籤:非同步io 同步 ndt window hide sock lin recvfrom 實現
一、複習 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 timeimport socketsk = 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() #--> 非阻塞,沒有串連來就報錯 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資源
非阻塞IO-server
import socketsk = 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 selectimport socketsk = 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 socketsk = 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 selectorsimport socketsel = 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 socketsk = 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多工