Python3-事件驅動、IO模型和觸發方式

事件驅動模型

傳統編程線性模型

開始  ---->   代碼塊A ---->代碼塊B ---->代碼塊C 。。。。。。 結束

每一個代碼塊都有各自實現的功能,按照條件語句順序判斷執行,每一次運行順序或許都不一樣,它的控制流程是由獲取的數據所和判斷語句所決定的。編程

事件驅動程序模型

開始  ---->  初始化  ---->  等待

事件驅動器啓動後,在等待事件觸發,而後作出相應的程序執行效果。觸發事件包括:輸入信息、鼠標、敲擊鍵盤、內部定時器等服務器


IO模型

synchronous 同步IO

一個進程在執行某個任務時,另一個進程必須等待其執行完畢,才能繼續執行網絡

所謂同步,就是在發出一個功能調用時,在沒有獲得結果以前,該調用就不會返回。按照這個定義,
其實絕大多數函數都是同步調用。可是通常而言,咱們在說同步、異步的時候,
特指那些須要其餘部件協做或者須要必定時間完成的任務。

asynchronous 異步IO

當一個異步功能調用發出後,調用者不能馬上獲得結果多線程

當該異步功能完成後,經過狀態、通知或回調來通知調用者。若是異步功能用狀態來通知,
那麼調用者就須要每隔必定時間檢查一次,效率就很低(有些初學多線程編程的人,總喜歡用一個循環去檢查某個變量的值,這實際上是一 種很嚴重的錯誤)。
若是是使用通知的方式,效率則很高,由於異步功能幾乎不須要作額外的操做。至於回調函數,其實和通知沒太多區別。

blocking 阻塞IO

調用結果返回以前,當前線程會被掛起併發

函數只有在獲得結果以後纔會
將阻塞的線程激活。有人也許會把阻塞調用和同步調用等同起來,實際上他是不一樣的。對於同步調用來講不少時候當前線程仍是激活的,只是從邏輯上當前函數沒有返回而已。

non-blocking 非阻塞IO

和阻塞IO對立app

在不能馬上獲得結果以前也會馬上返回,同時該函數不會阻塞當前線程

觸發方式

水平觸發

只有高電平(1)或低電平(0)的時候才觸發通知,只要在這兩種狀態就能獲得通知,只要有數據可讀,那麼水平觸發的epoll就當即返回異步

邊緣觸發

只有電平發生變化(高電平到低電平,或者低電平到高電平)的時候才觸發通知,有數據可讀,但沒有新的IO活動到來,epoll不會當即返回socket


multiplexing IO多路複用

select優缺點對比async

select:輪詢方式,遍歷每一個監聽對象是否有數據變更,效率較低函數

epoll:主動響應,主動提交數據變更提高效率

select模塊水平觸發實現併發IO多路複用

服務端

# -*- coding:utf8 -*-
import socket,select
test = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#定義socket通訊方式和通訊協議。socket.AF_INET基於網絡通訊,socket.SOCK_STREAM基於TCP協議
test.bind(('127.0.0.1',8000))                                   # 定義通訊ID
test.listen(5)                                                  # 定義最大通訊監聽數
inputs = [test,]                                                #定義監聽socket對象的列表
while True:
    r,w,e = select.select(inputs,[],[],5)                       # select監聽 socket 對象,後跟時間單位爲秒
    for obj in r:                                               # 遍歷監聽對象列表
        if obj == test:                                         # 判斷監聽對象是否和上次遍歷同樣
            conn,addr = obj.accept()                            # 被動接收套接字創建的鏈接
    print('accepted',conn,'from',addr)
            inputs.append(conn)                                 # 添加新socket對象到列表
        else:
            msg = obj.recv(1024)                                # 定義接收字節信息
            print('客戶端發送的消息是:', msg)
            obj.send(msg.upper())                               # 定義發送消息
    print("服務監聽中...")
服務監聽中...
客戶端發送的消息是: b'abc'
服務監聽中...
客戶端發送的消息是: b'aaa'
服務監聽中...

客戶端

# -*- coding:utf8 -*-
import socket
test = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#定義socket通訊方式和通訊協議。socket.AF_INET基於網絡通訊,socket.SOCK_STREAM基於TCP協議
test.connect(('127.0.0.1',8000))                #定義通訊ID,服務器的地址和端口
while True:
    inp = input(">>>").strip()                  #用戶輸入發送內容
    test.sendall(inp.encode('utf-8'))              #定義發送內容
    data = test.recv(1024)                      #定義接收字節信息
    print('收到服務端的發來的消息是:',data)
>>>abc
收到服務端的發來的消息是: b'ABC'
>>>aaa
收到服務端的發來的消息是: b'AAA'
>>>

selectors模塊實現併發IO多路複用

服務端

#-*- coding:utf-8 -*-
import selectors,socket
sel = selectors.DefaultSelector()                   # 操做系統自識別合適的IO多路複用方式

def accept(sock,mask):
    conn,addr = sock.accept()                       # 被動接收套接字創建的鏈接
    conn.setblocking(False)                         # 設置非阻塞
    sel.register(conn,selectors.EVENT_READ,read)    # conn 和 read 綁定,socket對象有活動調用accept方法
def read(conn,mask):
    try:                                            # 異常代碼檢測防止某個客戶端斷開鏈接致使服務終止
        data = conn.recv(1024)                      # 接收數據
        if not data:                                # 判斷是否接收到數據
            raise Exception
        conn.send(data.upper())                     # 接收到數據並返回數據
    except Exception as e:                          # 萬能異常
        sel.unregister(conn)                        # 沒有接收到數據,解除conn綁定的函數
        conn.close()                                # 關閉鏈接

sock = socket.socket()                              # 建立socket對象
sock.bind(('127.0.0.1',8000))                       # 定義通訊ID綁定對象
sock.listen(100)                                    # 定義最大通訊監聽數
sock.setblocking(False)                             # 設置非阻塞

sel.register(sock,selectors.EVENT_READ,accept)      # socket 和 accept 綁定,socket對象有活動調用accept方法

print("服務運行中....")
while True:
    events = sel.select()                           # 監聽socket對象
    for key,mask in events:                         # 遍歷events對象列表
        callback = key.data                         # 觸發socket綁定的函數accept
        callback(key.fileobj,mask)                  # 監聽到的有相應的socket對象
服務運行中....

客戶端

# -*- coding:utf8 -*-
import socket
test = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#定義socket通訊方式和通訊協議。socket.AF_INET基於網絡通訊,socket.SOCK_STREAM基於TCP協議
test.connect(('127.0.0.1',8000))                #定義通訊ID,服務器的地址和端口
while True:
    inp = input(">>>").strip()                  #用戶輸入發送內容
    test.sendall(inp.encode('utf-8'))           #定義發送內容
    data = test.recv(1024)                      #定義接收字節信息
    print('收到服務端的發來的消息是:',data)
>>>abc
收到服務端的發來的消息是: b'ABC'
>>>
相關文章
相關標籤/搜索