绿色线程API的纯Python实现

20 投票
2 回答
3274 浏览
提问于 2025-04-15 23:21

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模块的功能。

你也可以看看GogenKamelia,这些项目都有纯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

撰写回答