Python twisted:'defer.execute'和'threads.deferToThread'之间的区别`

Python twisted:'defer.execute'和'threads.deferToThread'之间的区别`,python,multithreading,twisted,deferred-execution,Python,Multithreading,Twisted,Deferred Execution,twisted中的defer.execute()和threads.deferToThread()之间有什么区别?两者都采用相同的参数—一个函数和调用它的参数—并返回一个延迟参数,该参数将与调用函数的结果一起触发 threads版本明确声明它将在线程中运行。但是,如果延迟版本没有,那么调用它有什么意义呢?在反应器中运行的代码不应该阻塞,因此它调用的任何函数都不应该阻塞。此时,您可以只执行defer.success(f(*args,**kwargs))而不执行defer.execute(f,args

twisted中的
defer.execute()
threads.deferToThread()
之间有什么区别?两者都采用相同的参数—一个函数和调用它的参数—并返回一个延迟参数,该参数将与调用函数的结果一起触发


threads
版本明确声明它将在线程中运行。但是,如果<代码>延迟版本没有,那么调用它有什么意义呢?在反应器中运行的代码不应该阻塞,因此它调用的任何函数都不应该阻塞。此时,您可以只执行
defer.success(f(*args,**kwargs))
而不执行
defer.execute(f,args,kwargs)
,并获得相同的结果。

defer.execute确实以阻塞方式在同一线程中执行函数,并且您的
defer.execute(f,args,kwargs)是正确的
的操作与
defer.success(f(*args,**kwargs))
相同,只是
defer.execute将返回一个回调,如果函数f引发异常,则该回调已触发errback。同时,在您的defer.success示例中,如果函数抛出异常,它将向外传播,这可能是不需要的

为了便于理解,我将在此处粘贴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
,它调用函数,如果函数已经返回了一个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
要在同步上下文中运行它,而不使用reactor,只需传递一个备用getter函数,如下所示:

from urllib2 import urlopen

def synchronous_getter(url):
    resp = urlopen(url)
    result = resp.read()
    resp.close()
    return result