0x00 基本概念
gevent是基于libev和greenlet的一个python异步框架。
libev是一个高性能的事件循环(event loop)实现。
事件循环(也称作IO多路复用),是解决阻塞问题,实现并发的一种方法。简单点说,就是event loop
会捕获、处理io
事件的变化:遇到阻塞,就跳出;阻塞结束,就继续。这依赖于系统底层的select
函数及其升级版:poll
和epoll
。《深入理解计算机系统》一书中,对此有深入探讨。
greenlet
是一个python
的协程管理、切换模块。通过greenlet
,你可以显式地在不同的任务之间切换。
0x01 Actor模式
Actor
是Erlang
语言的精髓。它强调基于消息传递的并发机制。
我们模仿这篇文章 建立一个actor模型。核心代码如下:
import genvet
# 主队列
queue = gevent.queue.JoinableQueue()
while True:
# 持续获取数据
try:
data = queue.get(timeout=5)
except Empty:
gevent.sleep(0.5)
continue
# 交付给Actor
if data:
gl = Actor(data)
g1.start()
g1.join()
Actor
为我们自定义的一个Greenlet
的子类,核心代码如下:
class Actor(Greenlet):
def __init__(self, data):
self.data = data
Greenlet.__init__(self)
def _run(self):
result = do_something(self.data)
return result
这样,我们这个Actor
可以从消息队列中接受数据,通过start()
,_run()
被调用。
由于gevent
和monkey patch
的存在,你基本可以以同步的方式,写出异步的代码。这样的写法显得很多余。但是,却可以很好的实现业务的分离,让代码更清晰,更容易维护和扩展。
0x02 实现回调
如果你还希望给Actor
加一个回调。即等他完成了之后,再进行某些处理。
那我们可以对Actor
机型如下修改:
class Actor(Greenlet):
def __init__(self, data):
self.data = data
Greenlet.__init__(self)
def _run(self):
# 通过self.link添加回调函数。
self.link(callback)
result = do_something(self.data)
return result
你可以通过Greenlet().link()
,给你的协程添加一个回调。这个回调函数只接收一个参数,即这个协程的实例(g1
)。我们会看到_run()
函数,其实是返回了一个结果result
的。那我们在回调函数中能否取得这个值呢。其实是可以的,这个值被存在了g1.value
中。
还是那句话,这样的设计,可能看起来很多余。但随着框架功能的增加,这样多余的设计会让你的代码,愈发地灵活。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。