8

defer.execute()和in 和有什么不一样threads.deferToThread()?两者都采用相同的参数 - 一个函数和调用它的参数 - 并返回一个 deferred,它将随着调用函数的结果而被触发。

threads版本明确声明它将在线程中运行。但是,如果defer版本没有,那么调用它又有什么意义呢?在反应器中运行的代码永远不会阻塞,因此它调用的任何函数都必须不会阻塞。那时,您可以做defer.succeed(f(*args, **kwargs))而不是defer.execute(f, args, kwargs)获得相同的结果。

4

1 回答 1

9

defer.execute 确实在同一个线程中以阻塞方式执行该函数,并且您是正确的,defer.execute(f, args, kwargs)除了defer.succeed(f(*args, **kwargs)) defer.execute返回一个回调,如果函数f抛出异常,则会触发 errback。同时,在您的 defer.succeed 示例中,如果函数抛出异常,它将向外传播,这可能是不希望的。

为了便于理解,我将在此处粘贴 defer.execute 的源代码:

def execute(callable, *args, **kw):
    """Create a deferred from a callable and arguments.

    Call the given function with the given arguments.  Return a deferred which
    has been fired with its callback as the result of that invocation or its
    errback with a Failure for the exception thrown.
    """
    try:
        result = callable(*args, **kw)
    except:
        return fail()
    else:
        return succeed(result)

换句话说,defer.execute这只是将阻塞函数的结果作为延迟的捷径,然后您可以向其中添加回调/错误返回。回调将使用正常的链接语义触发。看起来有点疯狂,但是在添加回调之前,延迟可以“触发”并且仍然会调用回调。


所以要回答你的问题,为什么这有用?嗯,defer.execute对于测试/模拟以及简单地将异步 api 与同步代码集成都很有用。

同样有用的是defer.maybeDeferredwhich 调用该函数,然后如果该函数已经返回一个 deferred 则简单地返回它,否则函数类似于defer.execute. 当您编写一个期望可调用的 API 时,这很有用,当被调用时会给您一个延迟,并且您也希望能够接受正常的阻塞函数。

例如,假设您有一个应用程序获取页面并使用它来执行操作。而且,出于某种原因,您需要针对特定​​用例以同步方式运行它,例如在单次 crontab 脚本中,或响应 WSGI 应用程序中的请求,但仍保持相同的代码库。如果您的代码看起来像这样,则可以这样做:

from twisted.internet import defer
from twisted.web.client import getPage

def process_feed(url, getter=getPage):
    d = defer.maybeDeferred(getter, url)
    d.addCallback(_process_feed)

def _process_feed(result):
    pass # do something with result here

要在没有反应器的同步上下文中运行它,您可以只传递一个备用​​ getter 函数,如下所示:

from urllib2 import urlopen

def synchronous_getter(url):
    resp = urlopen(url)
    result = resp.read()
    resp.close()
    return result
于 2010-09-10T17:10:51.583 回答