Gevent 库的使用
手动从0开始写一个协程调度功能,考虑的东西很多。对于当前的项目,时间不允许。考虑到B项目是python代码,所以就使用了gevent调度。gevent的patch功能,patch掉底层的io接口。这样就能做到不改业务一行代码,化同步为异步调用。
首先提一下 greenlet库。这个库才是真正提供协程切换的接口库。其实,我们只需要greenlet库就可以,按照之前的ucontext协程调度的方式,用greenlet提供的switch接口进行切换。可以理解为,greenlet和ucontext协程库提供的功能是一样的:都是提供最基本的切换协程功能。怎么调度?还得自己去封装。而gevent库就提供了这一层封装。gevent的两个核心组件:
提供协程对象的封装和协程切换的接口,使用这个接口,用户可以自己进行调度,无论是对称的,还是非对称的 2. libev:
事件反应堆,封装使用了原生的epoll池,抽象了事件的概念。比如最常用的事件:io事件,定时事件
gevent的架构原理
gevent是严格的非对称调度方式。有一个hub协程,其他的都是任务协程。
gevent严格遵循中心调度原则:
举一个简单的生产协程的例子:
使用姿势:
import gevent
# 封装的业务逻辑
def test_wrap():
pass
# 生成一个协程任务
A = gevent.spawn(test_wrap)
gevent.joinall([A])
生产协程:spawn解释:
class Greenlet(greenlet):
def __init__(self, run=None, *args, **kwargs):
hub = get_hub()
greenlet.__init__(self, parent=hub)
@classmethod
def spawn(cls, *args, **kwargs):
g = cls(*args, **kwargs)
g.start()
return g
def start(self):
if self._start_event is None:
self._start_event = self.parent.loop.run_callback(self.switch)
注册prepare事件,切换到hub里,准备调度
执行总的来说,做了两件事情:
def joinall(greenlets, timeout=None, raise_error=False, count=None):
if not raise_error:
# 注册事件,切到hub执行
wait(greenlets, timeout=timeout)
def wait(objects=None, timeout=None, count=None):
result = []
if count is None:
return list(iwait(objects, timeout))
def iwait(objects, timeout=None):
waiter = Waiter()
switch = waiter.switch
try:
count = len(objects)
for obj in objects:
# 注册事件到prepare的事件回调中
obj.rawlink(switch)
for _ in xrange(count):
# 保存上下文,设置好回来的路径,然后从这里切到hub协程
item = waiter.get()
finally:
# 执行到这里的时候,就说明协程任务执行完成了
for obj in objects:
unlink = getattr(obj, 'unlink', None)
if unlink:
try:
# 从prepare事件回调里,取出来该协程
unlink(switch)
...
gevent 需要注意的点:
总结来讲:
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8