协程 (单线程下实现并发)
进程:资源单位
线程:执行单位
协程:单线程下实现并发
并发:切换+保存状态
程序员自己通过代码自己检测程序中的IO
一旦遇到了IO自己通过代码切换
给操作系统的感觉就是你这个线程没有任何的IO 从而提升代码的运行效率
切换+保存状态一定能够提升效率吗?
1.当任务是IO密集型的情况下 提升效率
2.当任务是计算密集型的情况下 降低效率
接下来 我们进行验证
1.在计算密集型的情况下,通过切换+保存状态 效率到底是降低了还是提升了呢?
这是串行执行的时间:
# 串行执行 0.8540799617767334 import time def func1(): for i in range(10000000): i+1 def func2(): for i in range(10000000): i+1 start = time.time() func1() func2() stop = time.time() print(stop - start)
下面是切换+保存状态的执行时间:
#基于yield并发执行 1.3952205181121826 import time def func1(): while True: 10000000+1 yield def func2(): g=func1() for i in range(10000000): time.sleep(100) # 模拟IO,yield并不会捕捉到并自动切换 i+1 next(g) start=time.time() func2() stop=time.time() print(stop-start)
根据执行时间来看 明显效率是降低了
2.在IO密集型的情况下,通过切换+保存状态 效率到底是降低了还是提升了呢?
首先我们需要找到一个能够识别IO的工具,遇到IO就可以自动的切换
这里我们就用到了gevent模块
这是串行的执行结果:
from gevent import monkey;monkey.patch_all() from gevent import spawn import time ''' 注意 gevent模块没办法自动识别 time.sleep 等io情况 需要你手动配置一个参数 ''' def heng(): print('哼!') time.sleep(2) print('哼!') def ha(): print('哈!') time.sleep(3) print('哈!') start = time.time() heng() ha() print(time.time()-start) #5.041796445846558
下面是通过切换+保存状态来执行 利用gevent模块
from gevent import monkey;monkey.patch_all() from gevent import spawn import time ''' 注意 gevent模块没办法自动识别 time.sleep 等io情况 需要你手动配置一个参数 ''' def heng(): print('哼!') time.sleep(2) print('哼!') def ha(): print('哈!') time.sleep(3) print('哈!') start = time.time() g= spawn(heng) g1 = spawn(ha) g.join() g1.join() print(time.time()-start) #3.041301727294922
明显的看出在IO密集型的情况下 切换+保存状态能够提升效率
Gevent应用举例
利用协程实现并发
实现TCP服务端的并发
server端
import socket from gevent import monkey;monkey.patch_all() from gevent import spawn sk = socket.socket() sk.bind(('127.0.0.1', 8080)) sk.listen() def talk(conn): while True: try: data = conn.recv(1024) if len(data) == 0 :break print(data.decode('utf-8')) conn.send(b'hi') except ConnectionResetError as e: print(e) break conn.close() def server(): while True: conn,addr = sk.accept() spawn(talk,conn) if __name__ == '__main__': res = spawn(server) res.join()
client端 起了400个线程
from threading import Thread import socket def client(): sk = socket.socket() sk.connect(('127.0.0.1',8080)) while True: sk.send(b'hello') data = sk.recv(1024).decode('utf-8') print(data) for i in range(400): t = Thread(target=client) t.start()