【问题标题】:twisted: difference between `defer.execute` and `threads.deferToThread`扭曲:`defer.execute` 和 `threads.deferToThread` 之间的区别
【发布时间】:2011-04-10 20:08:29
【问题描述】:

twisted 中的defer.execute()threads.deferToThread() 有什么区别?两者都采用相同的参数 - 一个函数和调用它的参数 - 并返回一个 deferred,它将随着调用函数的结果而被触发。

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

【问题讨论】:

    标签: python multithreading twisted deferred-execution


    【解决方案1】:

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-07-14
      • 1970-01-01
      • 1970-01-01
      • 2021-12-25
      • 2020-05-10
      • 2014-09-20
      • 2010-10-28
      相关资源
      最近更新 更多