简体   繁体   English

使用扭曲和绿色按钮时出错

[英]Error when using twisted and greenlets

I'm trying to use twisted with greenlets, so I can write synchronous looking code in twisted without using inlineCallbacks. 我正在尝试将Twisted与greenlet一起使用,因此我可以在不使用inlineCallbacks的情况下以twisted形式编写同步外观的代码。

Here is my code: 这是我的代码:

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

There are 5 main parts: 有五个主要部分:

  • A sleep function, that starts a timer, then switches back to the parent greenlet. 睡眠功能会启动计时器,然后切换回父级greenlet。 When the timer goes off, it switches back to the greenlet that is sleeping. 当计时器关闭时,它会切换回正在休眠的greenlet。
  • A make_async decorator. 一个make_async装饰器。 This takes some synchronous looking code and runs it in a greenlet. 这需要一些看起来同步的代码,并在greenlet中运行它。 IT also returns a deferred so the caller can register callbacks when the code completes. IT还返回一个deferr,以便在代码完成后,调用方可以注册回调。
  • A wait_one function, which blocks the greenlet until the deferred being waited on resolves. 一个wait_one函数,该函数阻止greenlet直到延迟等待解决。
  • The inner function, which (when wrapped) returns a deferred, sleeps for a random time, and then passes the time it slept for to the deferred. 内部函数(在包装时)返回延迟的函数,它会休眠一段随机时间,然后将其睡眠的时间传递给延迟的函数。
  • The outer function, which calls inner(), waits for it to return, then prints the return value. 调用inner()的外部函数等待其返回,然后输出返回值。

When I run this code I get this output (Note the error on the last two lines): 运行此代码时,我得到以下输出(请注意最后两行的错误):

outer(): greenelet: <greenlet.greenlet object at 0xb729cc5c>
inner(): greenelet: <greenlet.greenlet object at 0xb729ce3c>
Sleeping for 0.545666723422 seconds...
sleep(): greenelet: <greenlet.greenlet object at 0xb729ce3c>
wait_one(): greenelet: <greenlet.greenlet object at 0xb729cc5c>
done
0.545666723422
Here
Exception twisted.python.failure.Failure: <twisted.python.failure.Failure <class 'greenlet.GreenletExit'>> in <greenlet.greenlet object at 0xb729ce3c> ignored
GreenletExit did not kill <greenlet.greenlet object at 0xb729ce3c>

Doing a bit of research I've found that: 经过一些研究,我发现:

  • The last line is logged by greenlet.c 最后一行由greenlet.c记录
  • The previous line is logged by python itself, as it's ignoring an exception raised in a del method. 上一行是python本身记录的,因为它忽略了del方法中引发的异常。

I'm having real trouble debugging this as I can't access the GreenletExit or twisted.python.failure.Failure exceptions to get their stack traces. 我在调试它时遇到了麻烦,因为我无法访问GreenletExittwisted.python.failure.Failure异常以获取其堆栈跟踪。

Does anyone have any ideas what I'm doing wrong, or how I get debug the exceptions that are being thrown? 有谁知道我在做什么错,或者我如何调试正在抛出的异常?

One other data point: If I hack wait_one() to just return immediately (and not to register anything on the deferred it is passed), the errors go away. 另一个数据点:如果我砍下wait_one()以便立即返回(并且不对延迟传递的任何内容进行注册),则错误会消失。 :-/ : - /

Rewrite your error callback in wait_one like this: 像这样在wait_one重写错误回调:

  def errback(failure):
    ## new code
    if g.dead:
        return
    ##
    if not active:
        g.throw(failure)
    else:
        reactor.callLater(0, g.throw, failure)

If greenlet is dead (finished running), there is no point throwing exceptions in it. 如果greenlet已死(运行结束),则没有任何异常抛出。

mguijarr's answer fixed the problem, but I wanted to write up how I got into this situation. mguijarr的答案解决了该问题,但我想写下我如何陷入这种情况。

I have three greenlets: 我有三个Greenlet:

  • {main} that's runing the reactor. {main}正在运行反应堆。
  • {outer} that's running outer(). {outer}正在运行external()。
  • {inner} that's rrunning inner(). {inner}正在运行inner()。

When the sleep finishes the {main} switches to {inner} which switches to {outer}. 睡眠完成后,{main}切换到{inner},后者切换到{outer}。 Outer then returns and raises GreenletExit in {inner}. 然后,外层返回并在{inner}中引发GreenletExit。 This propogates back to twisted. 这传播回扭曲。 It sees an exception being raised from callback(), and so invokes errback(). 它看到从callback()引发了异常,因此调用了errback()。 This tries to throw the exception into {outer} (which has already exited), and I hit the error. 这试图将异常抛出到{outer}中(已经退出),我遇到了错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM