绿色线程API的纯Python实现
greenlet这个包是gevent和eventlet用来处理异步输入输出的。它是用C语言写的扩展,所以在Jython或IronPython上不能使用。如果对性能没有特别要求,最简单的方式就是用纯Python来实现greenlet的接口。
下面是一个简单的例子:
def test1():
print 12
gr2.switch()
print 34
def test2():
print 56
gr1.switch()
print 78
gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()
这个例子应该输出12, 56, 34(而不是78)。
2 个回答
10
在纯Python中实现greenlet是不可能的。
更新:
- 用线程模拟greenlet的API是可以做到的,尽管从实际角度来看完全没用。
- 生成器是不能用来做这个的,因为它们只保存单个调用的状态。而greenlet可以保存整个调用栈。这意味着gevent可以使用在标准socket上实现的任何协议(比如httplib和urllib2模块)。而基于生成器的框架需要在软件的每一层都使用生成器,所以httplib和很多其他的包就没法用了。
12
这种事情可以通过协程来实现,协程从Python 2.5版本开始就已经内置在标准的Python发行版中了。如果IronPython等完全支持Python 2.5的所有特性(我相信它们是的),那么你应该可以使用这种写法。
想了解更多关于如何使用协程的信息,可以看看这篇文章 :) 特别是,你可能会对这份PDF感兴趣,作者在里面用纯Python构建了一个系统,提供了类似于无栈Python或Greenlet模块的功能。
你也可以看看Gogen或Kamelia,这些项目都有纯Python的协程实现,你可以直接使用或者作为自己实现的参考。可以看看这页,它对cogen
的使用方式进行了简单的介绍。
需要注意的是,这里提到的协程实现和greenlet
的实现之间有一些区别。纯Python的实现都使用某种外部调度器,但基本思路是一样的:它们为你提供了一种运行轻量级、协作式任务的方法,而不需要使用线程。此外,上面提到的两个框架都非常适合异步IO,就像greenlet
本身一样。
这是你发布的示例,但用cogen
重写了一下:
from cogen.core.coroutines import coroutine
from cogen.core.schedulers import Scheduler
from cogen.core import events
@coroutine
def test1():
print 12
yield events.AddCoro(test2)
yield events.WaitForSignal(test1)
print 34
@coroutine
def test2():
print 56
yield events.Signal(test1)
yield events.WaitForSignal(test2)
print 78
sched = Scheduler()
sched.add(test1)
sched.run()
>>> 12
>>> 56
>>> 34
这个版本比greenlet
的版本稍微明确一些(例如使用WaitForSignal
来明确创建一个恢复点),但你应该能理解大致的意思。
补充:我刚刚确认这个在jython上也能工作。
KidA% jython test.py
12
56
34