簡體   English   中英

使用扭曲和綠色按鈕時出錯

[英]Error when using twisted and greenlets

我正在嘗試將Twisted與greenlet一起使用,因此我可以在不使用inlineCallbacks的情況下以twisted形式編寫同步外觀的代碼。

這是我的代碼:

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

有五個主要部分:

  • 睡眠功能會啟動計時器,然后切換回父級greenlet。 當計時器關閉時,它會切換回正在休眠的greenlet。
  • 一個make_async裝飾器。 這需要一些看起來同步的代碼,並在greenlet中運行它。 IT還返回一個deferr,以便在代碼完成后,調用方可以注冊回調。
  • 一個wait_one函數,該函數阻止greenlet直到延遲等待解決。
  • 內部函數(在包裝時)返回延遲的函數,它會休眠一段隨機時間,然后將其睡眠的時間傳遞給延遲的函數。
  • 調用inner()的外部函數等待其返回,然后輸出返回值。

運行此代碼時,我得到以下輸出(請注意最后兩行的錯誤):

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>

經過一些研究,我發現:

  • 最后一行由greenlet.c記錄
  • 上一行是python本身記錄的,因為它忽略了del方法中引發的異常。

我在調試它時遇到了麻煩,因為我無法訪問GreenletExittwisted.python.failure.Failure異常以獲取其堆棧跟蹤。

有誰知道我在做什么錯,或者我如何調試正在拋出的異常?

另一個數據點:如果我砍下wait_one()以便立即返回(並且不對延遲傳遞的任何內容進行注冊),則錯誤會消失。 : - /

像這樣在wait_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的答案解決了該問題,但我想寫下我如何陷入這種情況。

我有三個Greenlet:

  • {main}正在運行反應堆。
  • {outer}正在運行external()。
  • {inner}正在運行inner()。

睡眠完成后,{main}切換到{inner},后者切換到{outer}。 然后,外層返回並在{inner}中引發GreenletExit。 這傳播回扭曲。 它看到從callback()引發了異常,因此調用了errback()。 這試圖將異常拋出到{outer}中(已經退出),我遇到了錯誤。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM