python - Twisted 中的合作 - 产生执行上下文
问题描述
下面是我的测试平台
from twisted.internet import defer, task
@defer.inlineCallbacks
def foo():
yield
print 'after yield in foo'
@defer.inlineCallbacks
def main(reactor):
d = foo()
yield
print 'after yield in main'
yield d
task.react(main)
我预计该yield
语句将使函数“产生执行上下文”(无论这在 Twisted 中意味着什么)并让另一个延迟来接管执行。对于那个特定的例子,我希望main()
开始执行,调用foo()
,它被包装inlineCallbacks
成一个deferred,然后产生让foo()
最终开始的执行。然后foo()
反过来也产生执行,所以最终打印行的顺序应该是
after yield in main
after yield in foo
由于某种原因,输出是
after yield in foo
after yield in main
在 Twisted 中实现协作多任务并让执行上下文转到另一个延迟队列的正确方法是什么?
解决方案
我预计 yield 语句将使函数“产生执行上下文”(无论这在 Twisted 中意味着什么),并让另一个 deferred 来接管执行。
根据您的观察,我认为您现在已经摆脱了这种期望。非常清楚,这不是yield
由inlineCallbacks
.
在这样的函数中yield
所做的是将一个值传递给蹦床。如果该值为 Deferred,则 trampoline 会暂停生成器的执行,直到 Deferred 触发。如果该值不是 Deferred,或者当 Deferred 使用一个值触发时,生成器将使用发送给它的该值恢复。
因此,既然yield
is 相同yield None
且None
不是 a Deferred
,这些yield
表达式只是一种昂贵的表达方式None
。
这也让您对如何实现您所说的目标有所了解。要暂停执行,Deferred
请在您希望恢复执行之前生成不会触发的 a。
在 Twisted 中实现协作多任务并让执行上下文转到另一个延迟队列的正确方法是什么?
有许多可能正确的方法可以做到这一点。具体细节更多地取决于您的特定应用要求。
不幸的是,有一些容易解释的俗气的答案可能看起来是正确的,但最终可能会导致性能不佳和维护成本高昂。例如,您可以暂停“反应堆迭代”(在这种情况存在的范围内,这可能比您想象的要少)。为此,yield twisted.internet.task.deferLater(reactor, 0.0, lambda: None)
。这个表达式使 a从现在开始不早于“零秒”触发,但也有它现在Deferred
不触发的约束。
但是,这让整个反应器实现有机会在您的发电机恢复之前完成工作 - 即使没有其他工作要做。因此,您为合作的可能性付出了巨大的 CPU 成本。此外,它通过引入基于时间的调度交互使功能难以测试。
Twisted 提供的一个替代方案是试图解决其中的一些困难,twisted.internet.task.cooperate
它inlineCallbacks
倾向于使用裸发电机。这些实际上确实用于yield
提供暂停点,但这样做的方式不会让整个反应堆有机会在恢复之前运行。这解决了一些 CPU 问题和可能的一些维护困难,尽管最终它仍然引入了一些基于时间的依赖关系。但是,至少可以在不涉及的情况下对裸生成器进行操作,cooperate
这在一定程度上减轻了这种困难(与inlineCallbacks
惯用编写的代码破坏底层生成器并仅提供返回Deferred
用于测试的函数的情况相比)。
推荐阅读
- python - pytest:是否可以在 Class setup/teardown 中使用 pytest-datadir 固定装置
- java - CloudFoundry 中部署的线程池代码不起作用
- java - 使用 com.fasterxml.jackson.core.JsonParser 作为 Jersey 客户端序列化器/反序列化器?
- python - 您如何存储单击命令行参数/选项以供参考?
- javascript - ngx-auth-firebaseui 在遵循指南后无法正常工作,有关 StyleUtils 的错误
- ruby-on-rails - 将 Rails 5.2 部署到生产环境时,哪种资产调试器配置有效?
- python-2.7 - 如何从 csv 文件(在 Linux 中)中的数据生成多个信号的脉冲序列的方波图?
- visual-c++ - Windows SDK 标头中面临的问题未递归包含在 Visual Studio 托管 C++ 项目中
- javascript - 画布已被 videojs 中的跨域数据污染
- python - 如何使用 nginx 和 uwsgi 部署 django