如果 __anext__
将控制权交还给事件循环(通过 await
或 call_soon
/call_later
),是否有可能在同一个实例上调用另一个 __anext__
,而第一个实例尚未解析,或者它们会排队?是否有任何其他情况假设只有一个 __anext__
同时运行是不安全的?
最佳答案
简答:使用 async for
不会重叠,但调用 __anext__
会重叠。
长答案:
这是我在玩 __anext__
机制时所做的:
import asyncio
class Foo(object):
def __init__(self):
self.state = 0
def __aiter__(self):
return self
def __anext__(self):
def later():
try:
print(f'later: called when state={self.state}')
self.state += 1
if self.state == 3:
future.set_exception(StopAsyncIteration())
else:
future.set_result(self.state)
finally:
print(f'later: left when state={self.state}')
print(f'__anext__: called when state={self.state}')
try:
future = asyncio.Future()
loop.call_later(0.1, later)
return future
finally:
print(f'__anext__: left when state={self.state}')
async def main():
print('==== async for ====')
foo = Foo()
async for x in foo:
print('>', x)
print('==== __anext__() ====')
foo = Foo()
a = foo.__anext__()
b = foo.__anext__()
c = foo.__anext__()
print('>', await a)
print('>', await b)
print('>', await c)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
loop.run_until_complete(asyncio.gather(*asyncio.Task.all_tasks()))
loop.close()
我已经实现了 __anext__
来返回 future,而不仅仅是 async def
,所以我可以更好地控制解决这些 futures 的中间步骤。
这是一个输出:
==== async for ====
__anext__: called when state=0
__anext__: left when state=0
later: called when state=0
later: left when state=1
> 1
__anext__: called when state=1
__anext__: left when state=1
later: called when state=1
later: left when state=2
> 2
__anext__: called when state=2
__anext__: left when state=2
later: called when state=2
later: left when state=3
==== __anext__() ====
__anext__: called when state=0
__anext__: left when state=0
__anext__: called when state=0
__anext__: left when state=0
__anext__: called when state=0
__anext__: left when state=0
later: called when state=0
later: left when state=1
later: called when state=1
later: left when state=2
later: called when state=2
later: left when state=3
> 1
> 2
~~~ dies with StopAsyncIteration ~~~
在 async for
的情况下,可以看到 __anext__
首先完成,然后事件循环启动并运行延迟安排的任何内容。如果 __anext__
正在堆叠,事件循环将借此机会安排另一个 __anext__
调用,直到延迟的 later
开始 - 相反,事件循环阻塞直到现在是稍后
运行的时间了。
因此,如果您的异步迭代器仅用于 async for
,可以安全地假设只有一个 __anext__
同时运行。
使用 __anext__
情况更糟:您可以随意堆叠它们。但是,如果您的 __anext__
是协同程序,那么这应该不是什么大问题——无论如何调用时它都不应该保持任何状态。或者至少我是这么认为的。
关于python - `async for` 的语义 - __anext__ 调用可以重叠吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43701647/