Python 使用twisted和greenlet时出错

Python 使用twisted和greenlet时出错,python,twisted,greenlets,Python,Twisted,Greenlets,我正在尝试将twisted与greenlets结合使用,这样我就可以在twisted中编写同步代码,而不必使用inlineCallbacks 这是我的密码: import time, functools from twisted.internet import reactor, threads from twisted.internet.defer import Deferred from functools import wraps import greenlet def make_asyn

我正在尝试将twisted与greenlets结合使用,这样我就可以在twisted中编写同步代码,而不必使用inlineCallbacks

这是我的密码:

import time, functools
from twisted.internet import reactor, threads
from twisted.internet.defer import Deferred
from functools import wraps
import greenlet

def make_async(func):
    @wraps(func)
    def wrapper(*pos, **kwds):
        d = Deferred()

        def greenlet_func():
            try:
                rc = func(*pos, **kwds)
                d.callback(rc)
            except Exception, ex:
                print ex
                d.errback(ex)

        g = greenlet.greenlet(greenlet_func)
        g.switch()

        return d
    return wrapper

def sleep(t):
    print "sleep(): greenelet:", greenlet.getcurrent()
    g = greenlet.getcurrent()
    reactor.callLater(t, g.switch)
    g.parent.switch()

def wait_one(d):
    print "wait_one(): greenelet:", greenlet.getcurrent()
    g = greenlet.getcurrent()
    active = True

    def callback(result):
        if not active:
            g.switch(result)
        else:
            reactor.callLater(0, g.switch, result)

    def errback(failure):
        if not active:
            g.throw(failure)
        else:
            reactor.callLater(0, g.throw, failure)

    d.addCallback(callback)
    d.addErrback(errback)

    active = False
    rc = g.parent.switch()
    return rc

@make_async
def inner():
    print "inner(): greenelet:", greenlet.getcurrent()

    import random, time
    interval = random.random()

    print "Sleeping for %s seconds..." % interval
    sleep(interval)
    print "done"

    return interval

@make_async
def outer():
    print "outer(): greenelet:", greenlet.getcurrent()
    print wait_one(inner())
    print "Here"

reactor.callLater(0, outer)
reactor.run()
共有5个主要部分:

  • 一个睡眠函数,启动计时器,然后切换回父greenlet。当计时器熄灭时,它会切换回正在睡觉的绿灯
  • make_异步装饰器。这需要一些同步的代码,并在greenlet中运行。它还返回一个延迟消息,以便调用方可以在代码完成时注册回调
  • 一个wait_one函数,它阻止greenlet,直到等待的延迟解决为止
  • 内部函数(包装时)返回一个deferred,休眠一段随机时间,然后将休眠时间传递给deferred
  • 调用inner()的外部函数等待它返回,然后打印返回值
当我运行这段代码时,我得到了这个输出(注意最后两行的错误):

outer():greenelet:
内部():greenelet:
睡眠0.545666723422秒。。。
sleep():greenelet:
等等,格林莱特:
完成
0.545666723422
在这里
异常twisted.python.failure.failure:处于忽略状态
绿色脱欧并没有造成死亡
通过一些研究,我发现:

  • 最后一行由greenlet.c记录
  • 前一行由python自己记录,因为它忽略了在del方法中引发的异常
调试这个时我遇到了真正的问题,因为我无法访问
GreenletExit
twisted.python.failure.failure
异常以获取它们的堆栈跟踪

有人知道我做错了什么,或者我如何调试抛出的异常吗


另一个数据点:如果我hack wait_One()立即返回(并且不在延迟传递的数据上注册任何内容),错误就会消失-/

wait\u one
中重写错误回调,如下所示:

  def errback(failure):
    ## new code
    if g.dead:
        return
    ##
    if not active:
        g.throw(failure)
    else:
        reactor.callLater(0, g.throw, failure)
如果greenlet已停止运行(已完成运行),则抛出异常没有意义
在它里面。

mguijarr的答案解决了这个问题,但我想写下我是如何陷入这种情况的

我有三个小菜:

  • {main}反应堆正在运行
  • {outer}正在运行outer()
  • {inner}这是rrunning inner()

睡眠结束后,{main}切换到{inner},后者切换到{outer}。然后,Outer返回并在{inner}中引发GreenletExit。这又回到了扭曲。它看到回调()引发异常,因此调用errback()。这试图将异常抛出到{outer}(它已经退出)中,我发现了错误

这篇文章解释了,一旦您以这种方式隐式地调度协同路由,您就不再真正“使用Twisted”,因为您没有从它的编程模型中获得好处:-此外,您可能对已经这样做的库感兴趣,而不是编写自己的库-
  def errback(failure):
    ## new code
    if g.dead:
        return
    ##
    if not active:
        g.throw(failure)
    else:
        reactor.callLater(0, g.throw, failure)