扭曲:“defer.execute”和“threads.deferToThread”之间的区别
在twisted中,defer.execute()
和threads.deferToThread()
有什么区别?两者都采用相同的参数 - 一个函数和调用它的参数 - 并返回一个 deferred ,它将随着调用函数的结果而被触发。
threads
版本明确指出它将在线程中运行。但是,如果 defer
版本没有,那么调用它还有什么意义呢?在反应器中运行的代码永远不应该阻塞,因此它调用的任何函数都必须不阻塞。此时,您可以使用 defer.succeed(f(*args, **kwargs))
而不是 defer.execute(f, args, kwargs)
来执行相同的结果。
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.
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
defer.execute 确实在同一线程中以阻塞方式执行该函数,并且您是正确的,因为 defer.execute(f, args, kwargs) 与 defer.succeed 的作用相同(f(*args, **kwargs)) 除了,如果函数 f,
defer.execute
将返回一个已触发 errback 的回调 抛出异常。同时,在您的 defer.succeed 示例中,如果函数抛出异常,它将向外传播,这可能是不希望的。为了便于理解,我将 defer.execute 的源代码粘贴在这里:
换句话说,defer.execute 只是将阻塞函数的结果作为延迟的快捷方式,然后您可以添加它回调/错误返回。回调将使用正常的链接语义来触发。这看起来有点疯狂,但 Deferreds 可以在添加回调之前“触发”,并且回调仍然会被调用。
因此,回答您的问题,为什么这有用?好吧,defer.execute 对于测试/模拟以及简单地将异步 api 与同步代码集成都很有用。
同样有用的是 defer.maybeDeferred ,它调用函数,然后如果函数已经返回 deferred 则简单地返回它,否则函数类似于 defer.execute 。当您编写一个需要可调用的 API 并在调用时为您提供延迟,并且您也希望能够接受正常的阻塞函数时,这非常有用。
例如,假设您有一个应用程序可以获取页面并使用它执行操作。而且,出于某种原因,您需要针对特定用例以同步方式运行它,例如在单次 crontab 脚本中,或响应 WSGI 应用程序中的请求,但仍保留相同的代码库。如果您的代码如下所示,则可以这样做:
要在没有反应器的同步上下文中运行此代码,您只需传递一个备用 getter 函数,如下所示:
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 asdefer.succeed(f(*args, **kwargs))
except thatdefer.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.For ease of understanding, I'll just paste the source of defer.execute here:
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.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.Also useful is
defer.maybeDeferred
which calls the function and then if the function already returns a deferred simply returns it, else functions similar todefer.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.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:
To run this in a synchronous context, without the reactor, you could just pass an alternate getter function, like so: