Twisted中的defer.execute()threads.deferToThread()有什么区别?两者都使用相同的参数-一个函数,以及使用该函数调用的参数-并返回一个deferred,该延迟将与调用该函数的结果一起触发。
threads版本明确声明它将在线程中运行。但是,如果没有defer版本,那么调用它会是什么意义呢?在 react 堆中运行的代码绝不应该阻塞,因此它调用的任何函数都必须不阻塞。那时,您可以只执行defer.succeed(f(*args, **kwargs))而不是defer.execute(f, args, kwargs)即可获得相同的结果。

最佳答案

defer.execute确实确实以阻塞方式在同一线程中执行了该函数,并且您的正确之处在于defer.execute(f, args, kwargs)defer.succeed(f(*args, **kwargs)) 相同,但除外,defer.execute将返回回调,如果函数 f 抛出该错误,则该回调已引发错误一个异常(exception)。同时,在延迟成功的示例中,如果函数引发异常,则它将向外传播,这可能是不希望的。

为了便于理解,我将在此处粘贴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只是将阻止函数的结果作为延迟的快捷方式,然后可以向其添加回调/错误返回。回调将使用常规的链接语义触发。似乎有些疯狂,但是Deferreds可以在添加回调之前“触发”,并且仍将调用这些回调。

因此,回答您的问题,这为什么有用?好吧,defer.execute对于测试/模拟以及简单地将异步api与同步代码集成在一起都是很有用的。
defer.maybeDeferred也很有用,它会调用该函数,然后如果该函数已经返回了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

关于python - 扭曲: `defer.execute`和 `threads.deferToThread`之间的区别,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3686608/

10-12 20:08