1、实现多个任务之间进行切换,yield、greenlet都没有实现检测I/O,greenlet在实现多任务切换下更简单
from greenlet import greenlet def eat(name): print(f"{name} eat 1") g2.switch('egon') # 切换 print(f"{name} eat 2") g2.switch() def play(name): print(f"{name} play 1") g1.switch() print(f"{name} play 2") g1 = greenlet(eat) g2 = greenlet(play) g1.switch('egon') # 程序从此处执行 egon eat 1 egon play 1 egon eat 2 egon play 2
2、一个协程遇到IO操作自动切换到其它协程(如何实现检测IO,yield、greenlet都无法实现,就用到了gevent模块(select机制))
2.1 gevent模块
可以轻松的实现并发或异步编程,在gevent中用到的主要模式是Greenlet,
2.1.1、遇到io阻塞时会自动切换任务 --只实现识别gevent可以识别的阻塞
# 遇到io阻塞会自动切换任务 import gevent,time def eat(name): print(f"{name} eat1") gevent.sleep(2) # 模拟io阻塞 print(f"{name} eat2") def play(name): print(f"{name} play1") gevent.sleep(2) print(f"{name} play2") start = time.time() g1 = gevent.spawn(eat,'alex') g2 = gevent.spawn(play,'alex') g1.join() g2.join() stop = time.time() print(stop-start) alex eat1 alex play1 alex eat2 alex play2 2.007000207901001
2.1.2、实际情况中的应用gevent 打补丁(monkey.patch_all()) 识别 所有阻塞
alex eat1
alex play1
alex eat2
alex play2
2.005999803543091
3、基于gvent模块实现并发的套接字通信
服务端:
# 基于 gevent from gevent import monkey;monkey.patch_all() import socket import gevent def Server(ip_port): server = socket.socket(socket.AF_INET,socket.SOCK_STREAM) server.bind(ip_port) server.listen(5) while True: conn,addr = server.accept() gevent.spawn(communicate,conn) server.close() def communicate(conn): while True: try: data = conn.recv(1024).decode('utf-8') conn.send(data.upper().encode('utf-8')) except Exception as e: print(e) break conn.close() if __name__ == '__main__': ip_port = ('127.0.0.1',8080) Server(ip_port) # g = gevent.spawn(Server,ip_port) # g.join()
客户端:启动500个线程模拟500个客户端向服务端发消息
import socket from threading import Thread,currentThread def client(): client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) ip_port = ('127.0.0.1',8080) client.connect(ip_port) while True: client.send(f"{currentThread().getName()} hello".encode('utf-8')) data = client.recv(1024) print(data.decode('utf-8')) client.close() if __name__ == '__main__': for i in range(500): t = Thread(target=client) t.start()