扭曲:`defer.execute`和`threads.deferToThread`之间的区别 [英] twisted: difference between `defer.execute` and `threads.deferToThread`

查看:250
本文介绍了扭曲:`defer.execute`和`threads.deferToThread`之间的区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

defer.execute()threads.deferToThread()在扭曲方面有什么区别?两者都采用相同的参数-一个函数,以及使用该参数调用它的参数-并返回一个deferred,该延迟将与调用该函数的结果一起触发.

What is the difference between defer.execute() and threads.deferToThread() in twisted? Both take the same arguments - a function, and parameters to call it with - and return a deferred which will be fired with the result of calling the function.

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

The threads version explicitly states that it will be run in a thread. However, if the defer version doesn't, then what would ever be the point of calling it? Code that runs in the reactor should never block, so any function it calls would have to not block. At that point, you could just do defer.succeed(f(*args, **kwargs)) instead of defer.execute(f, args, kwargs) with the same results.

推荐答案

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

defer.execute does indeed execute the function in a blocking manner, in the same thread and you are correct in that defer.execute(f, args, kwargs) does the same as defer.succeed(f(*args, **kwargs)) except that defer.execute will return a callback that has had the errback fired if function f throws an exception. Meanwhile, in your defer.succeed example, if the function threw an exception, it would propagate outwards, which may not be desired.

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

For ease of understanding, I'll just paste the source of defer.execute here:

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可以在添加回调之前触发",并且这些回调仍将被调用.

In other words, defer.execute is just a shortcut to take a blocking function's result as a deferred which you can then add callbacks/errbacks to. The callbacks will be fired with normal chaining semantics. It seems a bit crazy, but Deferreds can 'fire' before you add callbacks and the callbacks will still be called.

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

So to answer your question, why is this useful? Well, defer.execute is useful both for testing / mocking as well as simply integrating an async api with synchronous code.

defer.maybeDeferred也是有用的,它可以调用该函数,然后如果该函数已经返回了延迟,则仅返回它,否则类似于defer.execute的函数.当您编写一个期望可调用的API时,这很有用.调用时会延迟调用,并且您还希望能够接受常规的阻塞函数.

Also useful is defer.maybeDeferred which calls the function and then if the function already returns a deferred simply returns it, else functions similar to defer.execute. This is useful for when you write an API which expects a callable that when called gives you a deferred, and you want to be able to accept normal blocking functions as well.

例如,假设您有一个应用程序,该应用程序可以获取页面并对其进行处理.并且由于某种原因,您需要针对特定​​用例以同步方式运行此程序,例如在单次crontab脚本中,或者响应WSGI应用程序中的请求,但仍要保持相同的代码库.如果您的代码看起来像这样,则可以完成此操作:

For example, say you had an application which fetched pages and did things with it. And, for some reason, you needed to run this in a synchronous fashion for a specific use case, like in a single-shot crontab script, or in response to a request in a WSGI application, but still keep the same codebase. If your code looked like this, it could be done:

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函数,如下所示:

To run this in a synchronous context, without the reactor, you could just pass an alternate getter function, like so:

from urllib2 import urlopen

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

这篇关于扭曲:`defer.execute`和`threads.deferToThread`之间的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆