事件驅動,IO模型1.事件驅動;是一種編程方式(編程思想),與編程語言不要緊 事件之間互不影響,誰觸發誰執行 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p onclick="func()">點我呀</p> <script> function func() { alert('eric210') } </script> </body> </html>傳統事件監聽的方式:(佔用cpu資源) def f(): pass while 1: 鼠標檢測2.IO模型: IO (計算機用語):I/O輸入/輸出(Input/Output),分爲IO設備和IO接口兩個部分。 在POSIX兼容的系統上,例如Linux系統 [1], I/O操做能夠有多種方式,好比DIO(Direct I/O),AIO(Asynchronous I/O,異步I/O),Memory-Mapped I/O(內存映射I/O)等,不一樣 的I/O方式有不一樣的實現方式和性能,在不一樣的應用中能夠按狀況選擇不一樣的I/O方式。 IO多路複用:前面是用協程實現的IO阻塞自動切換,而協程的原理和在事件驅動的狀況下IO的自動阻塞的切換的學名叫===》IO多路複用 socketserver,多個客戶端鏈接,單線程下實現併發效果,就是多路複用。 同步IO和異步IO,阻塞IO和非阻塞IO分別是什麼,區別是什麼,不一樣的人在不一樣的上下文給出的答案是不一樣的,因此先限定一下本文上下 文本文討論的背景是Linux環境下的networkIO。 (1)用戶空間和內核空間:用戶空間沒法訪問內核空間 (2)進程切換:切換過程大量消耗時間 (3)進程的阻塞 (4)文件描述 (5)緩存I/O:很是消耗資源3.Stevens在文章中比較了五種IO Mode: (1)blocking IO(阻塞IO):blockingIO的特色就是在IO執行的兩個階段都被block了(阻塞,就是調用我(函數),我(函數) 沒有接收完數據或者沒有獲得結果以前,我不會返回。) import socket sk=socket.socket() sk.bind() sk.listen(3) # sk.setblocking()#過濾阻塞IO con,add=sk.accept() con.recv() con.send() 弊端:進程全程阻塞狀態,什麼都幹不了 實例: #server端 #author: wylkjj #date:2019/5/20 import socket sk = socket.socket() address=('127.0.0.1',8080) sk.bind(address) sk.listen(3) sk.setblocking(False) import time while 1: try: conn,add=sk.accept() while 1: data=conn.recv(1024) print(data.decode('utf8')) conn.sendall(data) conn.close() except Exception as e: print('error:',e) time.sleep(3) #clinet端 #author: wylkjj #date:2019/5/20 import socket sk = socket.socket() address=('127.0.0.1',8080) sk.connect(address) while 1: # inp=input(">>>:") sk.sendall('hello'.encode('utf8')) data=sk.recv(1024) print(data.decode('utf8')) (2)nonblocking IO(非阻塞IO):copy狀態也是阻塞的,可是其它狀態不是阻塞的,例如recv()屢次發送詢問(非阻塞,就是調 用我(函數),我(函數)當即返回,經過select通知調用者) 弊端:數據延遲,數據不能及時拿到 (3)IO multiplexing(IO多路複用):這個詞會陌生,可是select,epoll大概會明白,有些地方稱這種IO方式爲event driven IO select/epoll的好處在於單個process能夠同時處理多個網絡鏈接的IO基本原理就是select/epoll這個function會不斷的輪詢所 負責的全部socket,當某個socket有數據到達了,就通知用戶進程 select優勢:能夠同時監聽多個文件描述符實現併發效果。(跨平臺) epoll:大多數都用epoll,也能夠同時監聽多個文件描述符實現併發效果。 主權:因此IO多路複用的模型也屬於同步IO (4)signal driven IO(信號驅動IO,實際中不經常使用) (5)asynchronous IO(異步IO):進程再也不阻塞,注:只要有一點阻塞就不是異步IO(異步,就是我調用一個功能,不須要知道該 功能結果,該功能有結果後通知我(回調通知)。) synchronous IO(同步IO):除異步IO上面的都屬於同步IO(同步,就是我調用一個功能,該功能沒有結束前,我死等結果。)4. 注意區別:他們針對的對象是不一樣的 同步IO和異步IO的區別就在於:數據拷貝的時候進程是否阻塞 阻塞IO和非阻塞IO的區別就在於:應用程序的調用是否當即返回5.IO multiplexing(IO多路複用):select,epoll select:r,w,e=select.select([sk1,sk2],[],[],5),5表示監聽5秒,5秒一打印 select實例1:(select是一種水平觸發) #author: wylkjj #date:2019/5/20 #server端 import socket,select sk1 = socket.socket() address1=('127.0.0.1',8080) sk1.bind(address1) sk1.listen(3) sk2=socket.socket() address2=('127.0.0.1',8081) sk2.bind(address2) sk2.listen(3) while True: r,w,e=select.select([sk1,sk2],[],[]) print('rrr') for obj in r: conn,addr=obj.accept()#conn會變,臨時分配,可是鏈接的socket對象是同樣的 print('conn',conn) print("hellow") print('r:>>',r) #author: wylkjj #date:2019/5/20 #clinet1端 import socket sk = socket.socket() address=('127.0.0.1',8080) sk.connect(address) while 1: data=sk.recv(1024) print(data.decode('utf8')) inp=input(">>>:") sk.sendall(inp.encode('utf8')) #author: wylkjj #date:2019/5/20 #clinet2端 import socket sk = socket.socket() address=('127.0.0.1',8081) sk.connect(address) while 1: data=sk.recv(1024) print(data.decode('utf8')) inp=input(">>>:") sk.sendall(inp.encode('utf8')) 實例2:clinet同上同樣 #author: wylkjj #date:2019/5/20 #server端 import socket,select sk1 = socket.socket() address1=('127.0.0.1',8080) sk1.bind(address1) sk1.listen(3) sk2=socket.socket() address2=('127.0.0.1',8081) sk2.bind(address2) sk2.listen(3) while True: r,w,e=select.select([sk1,sk2],[],[]) # print('rrr') for obj in r: conn,addr=obj.accept()#conn會變,臨時分配,可是鏈接的socket對象是同樣的 print('conn',conn) print("hellow") print('r:>>',r) epoll既能夠採用水平觸發,也能夠採用邊緣觸發 水平觸發:也就是隻有高電平(1)或低電平(0)時才觸發通知,只要再這兩種狀態就能獲得新通知,只要有數據可讀(描述符 就緒)那麼水平觸發的epoll就當即返回 邊緣觸發:只有電平發生變化(高電平到低電平,或者低電平到高電平)的時候纔出發通知,即便有數據可讀,可是沒有新的IO 活動到來,epoll也不會當即返回。6.IO多路複用的併發聊天: 互動聊天: #author: wylkjj #date:2019/5/20 #模擬併發效果 #server端 import socket import select sk = socket.socket() address=('127.0.0.1',8800) sk.bind(address) sk.listen(3) inp=[sk,] while 1: inputs, outputs, errors = select.select(inp,[],[],) for obj in inputs: if obj==sk: conn,addr=sk.accept() print(conn) inp.append(conn) else: data=obj.recv(1024) print(data.decode('utf8')) Inputs=input('回答%s>>>'%inp.index(obj)) obj.sendall(Inputs.encode('utf8')) #author: wylkjj #date:2019/5/20 #clinet端 import socket,time sk = socket.socket() address=('127.0.0.1',8800) sk.connect(address) while 1: inp=input(">>>:") sk.sendall(inp.encode('utf8')) data = sk.recv(1024) print(data.decode('utf8')) #author: wylkjj #date:2019/5/20 #clinet端 import socket,time sk = socket.socket() address=('127.0.0.1',8800) sk.connect(address) while 1: inp=input(">>>:") sk.sendall(inp.encode('utf8')) data = sk.recv(1024) print(data.decode('utf8'))