Python 协程 gevent 模块

Python 协程 gevent 模块

文章目录

  • Python 协程 gevent 模块
    • 协程
    • 安装模块
    • 模拟协程
    • 猴子补丁


协程

协程 Coroutine,又称微线程,纤程,实现了在单线程下的并发

对于单线程下,多多少少程序中会出现 IO 操作,如果出现 IO 操作,系统会在此线程等待 IO 的时候,阻塞当前线程,剥夺其使用权限,切换给其他线程以保证系统运行效率。

那么,通过通过我们人为的方式,采用协程在程序中控制 单线程 下的所拥有的多个任务 其中的一个任务能在遇到 IO 阻塞 时就切换到另外一个任务去执行,保证 单线程下处于一直被调用的状态,操作系统并不知道协程的存在,它只知道线程

特点:

  • 协程只有在IO密集型的任务中才会发挥作用
  • 没有线程切换的开销, 协程的切换属于程序内部控制的切换,降低了系统资源占用,拥有极高的执行效率
  • 单一线程内就可以实现并发的效果,最大限度地利用 CPU 性能

安装模块

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])

Python 协程 gevent 模块_第1张图片

若是使用 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])	# 此操作可以上述两步合作一步

Python 协程 gevent 模块_第2张图片


猴子补丁

我们不可能在实际应用场景中出现上述的模拟操作行为,得实现真正的协程,那么这得用到 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])	# 此操作可以上述两步合作一步

打上补丁后成功实现协程,可以试试其他操作
Python 协程 gevent 模块_第3张图片

你可能感兴趣的:(Python,python)