三、Greenlet模块
Greenlet是python的一个C扩展,来源于Stackless python,旨在提供可自行调度的‘微线程’, 即协程。generator实现的协程在yield value时只能将value返回给调用者(caller)。 而在greenlet中,target.switch(value)可以切换到指定的协程(target), 然后yield value。greenlet用switch来表示协程的切换,从一个协程切换到另一个协程需要显式指定。 安装 :pip3 install greenlet
简介:
from greenlet import greenlet def eat(name): print(‘%s eat 1‘ %name) g2.switch(‘egon‘) print(‘%s eat 2‘ %name) g2.switch() def play(name): print(‘%s play 1‘ %name) g1.switch() print(‘%s play 2‘ %name) g1=greenlet(eat) g2=greenlet(play) g1.switch(‘egon‘)#可以在第一次switch时传入参数,以后都不需要
greenlet实现状态切换
有几个缺点
1.手动切换
2.不能规避I/O操作(睡眠)
gevent模块
安装:pip3 install gevent Gevent 是一个第三方库,可以轻松通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenlet, 它是以C扩展模块形式接入Python的轻量级协程。 Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。
介绍、安装
g1=gevent.spawn(func,1,,2,3,x=4,y=5)创建一个协程对象g1,spawn括号内第一个参数是函数名,如eat,后面可以有多个参数,可以是位置实参或关键字实参,都是传给函数eat的 g2=gevent.spawn(func2) g1.join() #等待g1结束 g2.join() #等待g2结束 #或者上述两步合作一步:gevent.joinall([g1,g2]) g1.value#拿到func1的返回值 #例:遇到io主动切换 from gevent import monkey;monkey.patch_all() import gevent import time def eat(): print(‘eat food 1‘) time.sleep(2) print(‘eat food 2‘) def play(): print(‘play 1‘) time.sleep(1) print(‘play 2‘) g1=gevent.spawn(eat) g2=gevent.spawn(play) gevent.joinall([g1,g2]) print(‘主‘)
用法介绍
真正能实现协程的模块gevent import gevent def eat(): print(‘eating1‘) print(‘eating2‘) g1 = gevent.spawn(eat) #创建一个协程对象g1 #执行输出为空,表示它还没执行。 import gevent def eat(): print(‘eating1‘) print(‘eating2‘) g1 = gevent.spawn(eat) #创建一个协程对象g1 g1.join() #等待g1结束 #执行输出: #eating1 #eating2
例子
geven 不能识别time.sleep() 需要用gevent.sleep() 或者导入一个模块monkey;monkey patch (猴子补丁)
#如果想让协程执行time.sleep()呢?由于默认,协程无法识别time.sleep()方法,需要导入一个模块monkey #monkey patch (猴子补丁) #用来在运行时动态修改已有的代码,而不需要修改原始代码。 from gevent import monkey;monkey.patch_all() # 它会把下面导入的所有的模块中的IO操作都打成一个包,gevent就能够认识这些IO了 import time import gevent def eat(): print(‘eating1‘) time.sleep(1) #延时调用 print(‘eating2‘) def play(): print(‘playing1‘) time.sleep(1) #延时调用 print(‘playing2‘) g1 = gevent.spawn(eat) #创建一个协程对象g1 g2 = gevent.spawn(play) g1.join() #等待g1结束 g2.join() #执行输出: eating1 playing1 eating2 playing2
使用
结论:
使用gevent模块来执行多个函数,表示在这些函数遇到IO操作的时候可以在同一个线程中进行切换
利用其他任务的IO阻塞时间来切换到其他的任务继续执行
前提是:
spawn来发布协程任务
join负责开启并等待任务执行结束
gevent本身不认识其他模块中的IO操作,但是如果我们在导入其他模块之前执行from gevent import monkey;monkey.patch_all() 这行代码,必须在文件最开头
gevent就能够认识在这句话之后导入的模块中的所有IO操作了
Gevent之同步与异步
from gevent import spawn,joinall,monkey;monkey.patch_all() import time def task(pid): """ Some non-deterministic task """ time.sleep(0.5) print(‘Task %s done‘ % pid) def synchronous(): # 同步 for i in range(10): task(i) def asynchronous(): # 异步 g_l=[spawn(task,i) for i in range(10)] joinall(g_l) print(‘DONE‘) if __name__ == ‘__main__‘: print(‘Synchronous:‘) synchronous() print(‘Asynchronous:‘) asynchronous() # 上面程序的重要部分是将task函数封装到Greenlet内部线程的gevent.spawn。 # 初始化的greenlet列表存放在数组threads中,此数组被传给gevent.joinall 函数, # 后者阻塞当前流程,并执行所有给定的greenlet任务。执行流程只会在 所有greenlet执行完后才会继续向下走。
实例
当一个任务执行时,依赖另外一个任务的结果时,这种情况不适合异步,只能用同步
Gevent之应用举例一
Gevent之应用举例二
原文地址:https://www.cnblogs.com/python-by-xiaoma/p/10300000.html
时间: 2024-10-03 22:38:33