【问题标题】:Pure python implementation of greenlet APIgreenlet API的纯python实现
【发布时间】:2011-02-25 17:59:26
【问题描述】:

greenlet 包被 gevent 和 eventlet 用于异步 IO。它是作为 C 扩展编写的,因此不适用于 Jython 或 IronPython。如果不关心性能,那么在纯 Python 中实现 greenlet API 的最简单方法是什么。

一个简单的例子:

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)。

【问题讨论】:

  • IronPython 和 Jython 在完全线程化并拥有自己的异步 IO 调用的 VM 上运行 - 你不使用它们吗?
  • 最终是的,但我正在考虑在添加 VM 特定版本之前编写一个纯 python 版本。这种形式的流量控制并不完全直观。
  • 根据对其中一个答案的评论,您的最终目标是在 IronPython 或 Jython 中使用 eventlet。那是行不通的——不是因为greenlets,而是因为libeventeventlet 封装并依赖于它的事件循环和反应器的C 库。您可以想象在本机 .NET 或 Java 事件循环之上重新实现整个 libevent API(至少如果您不关心性能,正如您所说的那样),但这是一大堆工作。

标签: python ironpython jython


【解决方案1】:

在纯 Python 中无法实现 greenlet。

更新:

  • 使用线程伪造 greenlet API 确实可行,即使对于所有实际目的完全无用
  • 生成器不能用于此,因为它们只保存单个帧的状态。 Greenlets 保存了整个堆栈。这意味着 gevent 可以使用在标准套接字之上实现的任何协议(例如 httplib 和 urllib2 模块)。基于生成器的框架需要在软件的所有层都使用生成器,因此 httplib 和大量其他软件包被丢弃了。

【讨论】:

  • 不可能或性能不佳?我们可以用线程伪造 greenlet API 吗?
  • 其实这很有意思。也许我们确实可以用线程伪造 greenlet API。但是,这并不实用,因为在这种情况下 gevent 和 eventlet 将为您提供您已经拥有的 API(如套接字),只是开销更大。
  • 纯python版本只能使用线程。但我认为,为 IronPython、Jython 提供特定于 VM 的 greenlet 实现会更有用——也许这将有助于采用 greenlet 作为 Python 的标准模块。
  • 他说得对,用生成器伪造这种东西是有区别的:你没有得到一个完整的堆栈,这是一个很大的区别。
  • 是的。这个答案是完全正确的。 “只使用生成器”正在成为对拥有真正协程的弱回应。生成器很棒,但它们不是完整的协程,需要更改代码以适应。
【解决方案2】:

这种事情可以通过自 2.5 版开始内置到标准 Python 发行版中的协程来实现。如果 IronPython 和 co 完全兼容 Python 2.5 的所有特性(我相信它们是),那么您应该能够使用这个习惯用法。

有关如何使用它们的更多信息,请参阅this post :) 具体来说,您将对PDF 感兴趣,作者使用纯 Python 构建一个系统,该系统提供与无堆栈 Python 或Greenlet 模块。

您可能还想查看GogenKamelia 的想法:这些项目都有纯python 协程实现,您可以采用或用作您自己实现的参考。看看this page 以温和地介绍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

【讨论】:

  • 这是一个很好的例子,但是我真的很感兴趣完全使用greenlet api,没有yield语句。我想在 Jython 和 IronPython 上启用需要 greenlet 的 eventlet。
  • @tristan:如果你想模拟像 greenlet 这样的东西,你必须接受这些想法并将它们包装在一个相同的 API 中。应该有可能想出一些接近的东西。我可以试一试,向您展示这样的东西,但我认为您需要接受所展示的内容并运行它!显然 greenlet 本身是不可用的,但这表明这些原则可以继承并且可以重用。
  • 您的帖子中有拼写错误。它应该是 Cogen 而不是 Gogen
猜你喜欢
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 2020-11-15
  • 2020-02-25
  • 1970-01-01
  • 1970-01-01
  • 2014-08-13
  • 2016-12-01
相关资源
最近更新 更多