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.maybeDeferred
which 调用该函数,然后如果该函数已经返回一个 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