一、gevent. 在遇到io操做時會發生切換,切換gevent.joinall()中的gevent.spawn(a)去執行。python
使用非gevent封裝的sleep()時會發生阻塞服務器
import gevent import time def a(): print("begin a",time.time()) time.sleep(1) print("end a ",time.time()) def b(): print("begin b",time.time()) time.sleep(1) print("end b ",time.time()) def c(): print("begin c",time.time()) time.sleep(1) print("end c ",time.time()) if __name__ == "__main__": gevent.joinall([ gevent.spawn(a), gevent.spawn(b), gevent.spawn(c),] ) 運行結果: begin a 1466328299.3592122 end a 1466328300.3595576 begin b 1466328300.3595576 end b 1466328301.3598628 begin c 1466328301.3598628 end c 1466328302.3601925
二、使用gevent.sleep(1)時是非阻塞的。可是固然這個sleep(1)睡眠1秒仍是要經歷的,只是a在睡眠時能夠切換到b或c去執行:socket
將上面的time.sleep(1)改成gevent.sleep(1)spa
gevent.sleep(1) 運行結果: begin a 1466328564.0706365 begin b 1466328564.0891385 begin c 1466328564.089639 end a 1466328565.0892923 end c 1466328565.0907917 end b 1466328565.0907917
三、在文件最開始使用from gevent import monkey;monkey.patch_all() 能夠使time.sleep(1)爲非阻塞。這樣就不用gevent的sleep(1)了。線程
四、gevent實現單線程socket容許同時多個鏈接同時發生數據。 也能夠使用from gevent import socket,這樣就不用使用monkey.patch_all()了。code
簡單示例代碼:server
# 服務器端 import gevent import time import socket from gevent import monkey;monkey.patch_all() def server(port): s = socket.socket() s.bind(('127.0.0.1',port)) s.listen(50) # s.setblocking(False) while True: conn, addr = s.accept() # 接收客戶端鏈接 print("來了一個鏈接:",addr) gevent.spawn(handle_switch,conn) # gevent.spawn()裏的handle_switch()內部會非阻塞狀態 def handle_switch(conn): while True: try: data = conn.recv(1024) # 非阻塞,並不表明會往下執行,在這裏而是發生切換。 except ConnectionResetError as e: print(e) conn.close() break conn.send(data) # 非阻塞 print("recv:",data.decode()) if not data: conn.close() print("客戶端正常關閉") break if __name__ == "__main__": server(9001) # 客戶端 import socket s = socket.socket() s.connect(('127.0.0.1',9001)) while True: data = input(">> ").strip() if data == "": continue if data == "q": s.close() break s.send(bytes(data,encoding="utf-8")) data = s.recv(1024) print("recv:",data.decode())
發起兩個鏈接:blog
容許結果:進程
來了一個鏈接: ('127.0.0.1', 55801) # 第一個客戶端鏈接 recv: asd recv: asd 來了一個鏈接: ('127.0.0.1', 55804) # 第二個客戶端鏈接 recv: sdfa recv: asdg recv: 1 recv: 1 recv: 2 recv: 2 recv: 1 recv: 2 recv: # 客戶端1斷開鏈接,data爲空 客戶端正常關閉 # 客戶端1正常斷開,即客戶端是s.close()的 recv: haha recv: # 客戶端2斷開鏈接,data爲空 客戶端正常關閉 # 客戶端1正常斷開,即客戶端是s.close()的 來了一個鏈接: ('127.0.0.1', 55820) # 第三個客戶端鏈接 recv: asd [WinError 10054] 遠程主機強迫關閉了一個現有的鏈接。 # 客戶端3非正常鏈接,應該是被kill掉了進程,客戶端發送rst包。