协程 Coroutine,又称微线程,纤程,实现了在单线程下的并发
对于单线程下,多多少少程序中会出现 IO 操作,如果出现 IO 操作,系统会在此线程等待 IO 的时候,阻塞当前线程,剥夺其使用权限,切换给其他线程以保证系统运行效率。
那么,通过通过我们人为的方式,采用协程在程序中控制 单线程 下的所拥有的多个任务 其中的一个任务能在遇到 IO 阻塞 时就切换到另外一个任务去执行,保证 单线程下处于一直被调用的状态,操作系统并不知道协程的存在,它只知道线程。
特点:
gevent 模块 属于 第三方模块,需要进行安装后才能使用
在 cmd 命令终端中输入 安装命令
pip install gevent
这种方法是直接在国外服务器下载,下载速度比较忙,可以使用国内镜像源下载
这里使用的是 清华源
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple/ gevent
gevent.sleep() 此方法可以理解成 time 模块下的 sleep() 方法,都是休眠操作,让程序睡着,通过这种方法模拟程序遇到IO操作所造成的阻塞
之所以要用到这个gevent.sleep() 方法,那是因为在使用 gevent 实现协程时,展示模拟的是 gevent 可以识别的 IO 阻塞,若是 time.sleep() 方法,gevent是不能直接识别的
import gevent
import random
def funx1(num):
for i in range(1, num+1):
print(f"\033[1;31m功能1 第{i}次遇到IO操作\033[0m")
gevent.sleep(random.randint(1, 3)) # 在未打补丁下使用 gevent.sleep 模拟IO阻塞
print("功能1 完成运行")
def funx2(num):
for i in range(1, num+1):
print(f"\033[1;32m功能2 第{i}次遇到IO操作\033[0m")
gevent.sleep(random.randint(1, 5)) # 在未打补丁下使用 gevent.sleep 模拟IO阻塞
print("功能2 完成运行")
f1 = gevent.spawn(funx1, 10)
f2 = gevent.spawn(funx2, 10)
gevent.joinall([f1, f2])
若是使用 time.sleep() 则不能实现协程效果
import gevent
import random
def funx1(num):
for i in range(1, num+1):
print(f"\033[1;31m功能1 第{i}次遇到IO操作\033[0m")
time.sleep(random.randint(1, 3)) # 在未打补丁下使用 time.sleep() 模拟IO阻塞
print("功能1 完成运行")
def funx2(num):
for i in range(1, num+1):
print(f"\033[1;32m功能2 第{i}次遇到IO操作\033[0m")
time.sleep(random.randint(1, 5)) # 在未打补丁下使用 time.sleep() 模拟IO阻塞
print("功能2 完成运行")
f1 = gevent.spawn(funx1, 10)
f2 = gevent.spawn(funx2, 10)
# f1.join()
# f2.join()
gevent.joinall([f1, f2]) # 此操作可以上述两步合作一步
我们不可能在实际应用场景中出现上述的模拟操作行为,得实现真正的协程,那么这得用到 gevent.monkey
gevent.monkey
本模块的主要目的是仔细修补标准库的部分,使其具有与原始库相同的、对gevent友好的功能(至少尽可能接近)。
它的主要接口是 patch_all() 函数,执行所有可用的修补程序。它接受参数来限制对某些模块的修补,但大多数程序 应该 使用默认值,因为它们接收最广泛的测试,并且一些monkey补丁依赖于其他补丁。
值得注意的是,使用 monkey.patch_all() 打补丁操作时,应放到代码开头,保障补丁的可靠
from gevent import monkey; monkey.patch_all() # 需要将补丁放到开头
import gevent
import random
def funx1(num):
for i in range(1, num+1):
print(f"\033[1;31m功能1 第{i}次遇到IO操作\033[0m")
time.sleep(random.randint(1, 3))
print("功能1 完成运行")
def funx2(num):
for i in range(1, num+1):
print(f"\033[1;32m功能2 第{i}次遇到IO操作\033[0m")
time.sleep(random.randint(1, 5))
print("功能2 完成运行")
f1 = gevent.spawn(funx1, 10)
f2 = gevent.spawn(funx2, 10)
# f1.join()
# f2.join()
gevent.joinall([f1, f2]) # 此操作可以上述两步合作一步