【问题标题】:How do I run `n` python coroutines concurrently?如何同时运行“n”个 python 协程?
【发布时间】:2017-01-06 21:27:15
【问题描述】:

我用async def 创建了一个async python 协程,我想在列表中的每个元素上运行它。

但是,协程启动了一个单独的进程,我的电脑资源有限,所以我只想同时运行这些协程中的n。当一个完成后,我希望另一个开始。

我还在学习asyncio,但我不知道如何在这个框架内做到这一点。

我知道我可以使用类似这样的方法同时运行 n 作业:

commands = asyncio.gather(*[run_command(f) for f in islice(my_large_list,n)])
# Run the commands
results = loop.run_until_complete(commands)

但是,我不知道如何在每个作业完成后替换它。

【问题讨论】:

  • 您想将multiporcessingasyncio 一起使用吗?如果是这样的话:我用踏板试过了;不完全相同,但可能会让您知道如何到达那里,
  • 我真的不想在 asyncio 中使用多处理。我正在尝试调用外部进程...另一种说法:我想要并发,而不是并行。
  • 对不起,我很困惑... asyncio 将在单个线程上运行;无需担心资源有限。 otoh:启动进程导致并行(不是并发)。那是哪一个?你能发布一个你的协程的玩具例子吗? (我很想知道你是如何await 一个你开始的过程)。
  • @hiroprotagonist 我正在运行 python 程序单线程,但它正在使用asyncio.create_subprocess_exec 创建子进程。然而,这个问题是关于如何在某种队列中一次只运行n async 协程。

标签: python-3.x python-asyncio


【解决方案1】:

一种选择是使用asyncio.Semaphore

import asyncio

import random

s = asyncio.Semaphore(5)


async def my_coroutine(i):
    async with s:
        print("start", i)
        await asyncio.sleep(random.uniform(1, 3))
        print("end", i)


loop = asyncio.get_event_loop()
tasks = [my_coroutine(i + 1) for i in range(50)]
loop.run_until_complete(asyncio.gather(*tasks))
loop.close()

更新concurrent.futures 可能会比 asycnio 更容易地解决您的问题,因为 executors 有一个非常简单的 max_workers 参数:

import concurrent.futures
import time

import random


def my_routine(i):
    print("start", i)
    # Here you can use subprocess.* for anything, instead we will sleep:
    time.sleep(random.uniform(1, 3))
    print("end", i)
    return "i={}".format(i)


with concurrent.futures.ProcessPoolExecutor(max_workers=5) as executor:
    jobs = {executor.submit(my_routine, i + 1) for i in range(50)}
    for fut in concurrent.futures.as_completed(jobs):
        print(fut.result())

print('done')

【讨论】:

  • 我认为对于IO任务,ThreadPoolExecutor优于ProcessPoolExecutor
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-25
  • 2018-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-04
相关资源
最近更新 更多