简体   繁体   English

如何在 Python 中同时迭代和运行 AsyncGenerator

[英]How to iterate and run AsyncGenerator concurrently in Python

A bit new to Python, not sure if this question is too naive.对 Python 有点陌生,不知道这个问题是不是太天真了。 Trying to grasp the concurrency model.试图掌握并发模型。

Third party function (from the library) connects to multiple hosts through ssh and perform some bash command.第三方函数(来自库)通过 ssh 连接到多个主机并执行一些 bash 命令。 This function returns AsyncGenerator.此函数返回 AsyncGenerator。

Then my code iterates through this AsyncGenerator using async for :然后我的代码使用async for遍历这个 AsyncGenerator:

        # some code before
        asyncgenerator_var = # ...
        async for (host, exit_code, stdout, stderr) in asyncgenerator_var:
            if exit_code != 0:
                self.err(f"[{host}]: {''.join(decode_strings(stderr))}")
                continue
            self.out(f"[{host}]: {''.join(decode_strings(stdout))}")
            self.err(f"[{host}]: {''.join(decode_strings(stderr))}")
        # some code after

And then code calls await on this function.然后代码调用 await 这个函数。 But if runs one after another.但是如果一个接一个地运行。 Not concurrently.不是同时的。

Code someone explain why is that?代码有人解释为什么会这样? And what should be done to make it run concurrently.以及应该做些什么来使它同时运行。

In async model, no functions are run simultaneously.在异步模型中,没有函数同时运行。 The event loop may switch functions if the current function is await -ing other functions / futures.如果当前函数正在await其他函数/未来,则事件循环可能会切换函数。

The async for statement essentially means the event loop may run other scheduled callbacks/tasks between iterations. async for语句本质上意味着事件循环可以在迭代之间运行其他计划的回调/任务。

The async for body still run in the order yielded by the async generator.主体的async for仍然按照异步生成器产生的顺序运行。

To run the body in arbitrary order, wrap it inside an async function.要以任意顺序运行主体,请将其包装在异步函数中。 Create a separate task for each input, and finally gather the results of all tasks.为每个输入创建一个单独的任务,最后gather所有任务的结果。

# some code before

asyncgenerator_var =  # ...

async def task(host, exit_code, stdout, stderr):
    if exit_code != 0:
        self.err(f"[{host}]: {''.join(decode_strings(stderr))}")
        return 
    self.out(f"[{host}]: {''.join(decode_strings(stdout))}")
    self.err(f"[{host}]: {''.join(decode_strings(stderr))}")
    
tasks = []
async for (host, exit_code, stdout, stderr) in asyncgenerator_var:
    tasks.append(asyncio.create_task(task, host, exit_code, stdout, stderr))

await asyncio.gather(*tasks)
    
# some code after

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM