defer.execute 确实在同一个线程中以阻塞方式执行该函数,并且您是正确的,defer.execute(f, args, kwargs) 与 defer.succeed(f(*args, **kwargs)) 相同 except 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 只是将阻塞函数的结果作为延迟的快捷方式,然后您可以添加回调/错误返回。回调将使用正常的链接语义触发。看起来有点疯狂,但是 Deferred 可以在你添加回调之前“触发”并且回调仍然会被调用。
那么回答你的问题,为什么这很有用?好吧,defer.execute 对于测试/模拟以及简单地将异步 api 与同步代码集成都很有用。
defer.maybeDeferred 也很有用,它调用函数,然后如果函数已经返回 deferred,则简单地返回它,否则类似于 defer.execute 的函数。当您编写一个 API 时,该 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