1. 程式人生 > >python全棧開發day36-IO多路復用

python全棧開發day36-IO多路復用

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 = []
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(bhello) 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 socket

sk = socket.socket()
sk.connect((127.0.0.1,9000))
while True:
    print(sk.recv(1024))
    sk.send(bbye)
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(bhello)

# socketserver
# TCP協議的並發操作 selectors + 多線程
多路復用IO-select-sever 技術分享圖片
import socket

sk = socket.socket()
sk.connect((127.0.0.1,9000))
while True:
    sk.send(bwahaha)
    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多路復用