1 回答

TA貢獻1813條經驗 獲得超2個贊
不幸的是,這是正確的——yield
在 nursery 或 cancel 范圍內不受支持,除非在用于@contextlib.asynccontextmanager
創建異步上下文管理器或編寫異步 pytest fixture 的狹窄情況下。
有幾個原因。其中一些是技術性的:Trio 必須跟蹤哪些 nurseries/cancel 作用域當前在堆棧中處于“活動”狀態,當你離開yield
一個時,它會破壞嵌套,Trio 無法知道你已經完成這。(庫無法檢測出yield
上下文管理器。)
但還有一個根本的、無法解決的原因,那就是Trio和結構化并發的整個思想是,每個任務都“屬于”一個父任務,如果子任務崩潰,父任務可以收到通知。但是當你yield
在一個生成器中時,生成器框架會被凍結并與當前任務分離——它可能會在另一個任務中恢復,或者根本不會恢復。所以當你yield
,這打破了托兒所中所有子任務和他們父母之間的聯系。只是沒有辦法將其與結構化并發的原則相協調。
如果我運行以下
async def arange(*args):
? ? for val in range(*args):
? ? ? ? yield val
async def break_it():
? ? async with aclosing(delay(0, arange(3))) as aiter:
? ? ? ? with trio.move_on_after(1):
? ? ? ? ? ? async for value in aiter:
? ? ? ? ? ? ? ? await trio.sleep(0.4)
? ? ? ? ? ? ? ? print(value)
trio.run(break_it)
然后我得到
RuntimeError: Cancel scope stack corrupted: attempted to exit
<trio.CancelScope at 0x7f364621c280, active, cancelled> in <Task
'__main__.break_it' at 0x7f36462152b0> that's still within its child
<trio.CancelScope at 0x7f364621c400, active>
This is probably a bug in your code, that has caused Trio's internal
state to become corrupted. We'll do our best to recover, but from now
on there are no guarantees.
Typically this is caused by one of the following:
? - yielding within a generator or async generator that's opened a cancel
? ? scope or nursery (unless the generator is a @contextmanager or
? ? @asynccontextmanager); see https://github.com/python-trio/trio/issues/638 [...]
通過更改超時和延遲,使超時在生成器內部而不是在生成器外部過期,我還能夠得到一個不同的錯誤:trio.MultiError: Cancelled(), GeneratorExit() raised out of aclosing()
添加回答
舉報