python - `async for` 的语义 - __anext__ 调用可以重叠吗?

标签 python python-3.x asynchronous python-asyncio

如果 __anext__ 将控制权交还给事件循环(通过 awaitcall_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/

相关文章:

python - 连接python中多个大文件的每第n行

c# - 在同一 HTTP 请求 ASP.NET Core C# 中混合异步和同步

javascript - 将 JS 函数添加到并行队列

python - 在 Django 中,如何获取 URI 解析到的基于类的 View 的实例?

python 2.7 到 python 3.2 字符串格式错误

python - Azure Blob 存储 : Download blob with SAS token

python-3.x - 属性错误: Python 'filter' object has no attribute 'sort'

调用时 Javascript 代码不可用

python - 如何对字符串形式的数字列表的数据框列求和?

python - 在 Python OpenCV2 中打开多 channel 图像