【问题标题】:Why can Python coroutines not be called recursively?为什么不能递归调用 Python 协程?
【发布时间】:2014-05-04 04:20:51
【问题描述】:

我一直在使用 Python 协程而不是线程,并取得了一些成功。我突然想到我可能需要一个知道自己的协程,所以它可以给自己发送一些东西。我发现这是不可能的(无论如何在 Python 3.3.3 中)。为了测试,我写了以下代码:

def recursive_coroutine():
    rc = (yield)
    rc.send(rc)

reco = recursive_coroutine()
next(reco)
reco.send(reco)

这引发了一个异常:

Traceback (most recent call last):
  File "rc.py", line 7, in <module>
    reco.send(reco)
  File "rc.py", line 3, in recursive_coroutine
    rc.send(rc)
ValueError: generator already executing

虽然错误很明显,但感觉这应该是可能的。我从来没有想出一个有用的、现实的递归协程应用程序,所以我不是在寻找特定问题的答案。除了实施困难之外,还有其他原因是不可能的吗?

【问题讨论】:

    标签: python recursion generator coroutine


    【解决方案1】:

    这是不可能的,因为send 要工作,协程必须等待输入。 yield 暂停协程,sendnext 取消暂停。如果生成器正在调用send,则不能同时暂停并等待输入。

    如果你可以 send 到一个未暂停的协程,语义会变得非常奇怪。假设rc.send(rc) 行有效。然后send 将从中断处继续执行协程,即发送调用...但send 没有返回值,因为我们没有达到产量。

    假设我们返回一些虚拟值并继续。然后协程将执行到下一个yield。到那时,会发生什么?执行是否倒带,所以send 可以返回产生的值? yield 是否丢弃该值?控制流去哪儿了?没有好的答案。

    【讨论】:

    • 我希望 send 在协程中的下一个可用 yield 处开始执行(示例中不存在,但是...)
    • @gens:你怎么知道下一个可用的yield 是什么?如果它在循环、条件或with 块中怎么办?跳到下一个收益,无论“下一个”是什么意思,都不是特别有用的行为。
    • 我明白你的意思,为什么“下一个yield”不清楚。但是,我不相信没有比提出例外更好的答案了。如果send 只是将发送的值放在输入队列中并且例程将继续运行(就像它已经运行的那样)会怎样。当它遇到后续的yield 时,它会将最新的值从输入队列中弹出并返回。如果队列为空,它会像今天一样暂停。
    • @gens: 然后send 必须返回两次,一次是为了协程可以继续到下一个yield,一次是在遇到yield 时。您还会遇到队列永远不会清空的问题,因为如果sends 领先于yields,则没有什么可以让yields 赶上。
    • 如果你真的很努力,做出很多武断的决定,并处理很多边缘情况,你可以从整个混乱中得到某种确定的行为。但是,对于没有真正的用例来说,这太复杂了。
    猜你喜欢
    • 2013-11-25
    • 1970-01-01
    • 2017-12-01
    • 1970-01-01
    • 2017-08-10
    • 2016-02-04
    • 1970-01-01
    • 1970-01-01
    • 2021-10-01
    相关资源
    最近更新 更多