是否可以限制在asyncio中正常运行的协同程序的数量?

Bla*_*ard 14 python python-asyncio

我已经使用asyncio编写了我的脚本,但发现同时运行的协同程序的数量太大而且经常会出现问题.

所以我想同时限制协同程序的数量,一旦达到限制,我想等待任何协同程序在另一个程序执行之前完成.

我目前的代码如下:

loop = asyncio.get_event_loop()
p = map(my_func, players)
result = loop.run_until_complete(asyncio.gather(*p))

async def my_func(player):
    # something done with `await`
Run Code Online (Sandbox Code Playgroud)

players类型是list与包含大量元素(比如,12000).它需要大量的计算资源来同时运行所有这些,asyncio.gather(*p)所以我宁愿同时运行的玩家数量为200.一旦达到199,我希望另一个协程开始执行.

在asyncio中这可能吗?

Dav*_* L. 12

您可以包装您的收集并强制执行信号量:

import asyncio

async def semaphore_gather(num, coros, return_exceptions=False):
    semaphore = asyncio.Semaphore(num)

    async def _wrap_coro(coro):
        async with semaphore:
            return await coro

    return await asyncio.gather(
        *(_wrap_coro(coro) for coro in coros), return_exceptions=return_exceptions
    )

# async def a():
#     return 1

# print(asyncio.run(semaphore_gather(10, [a() for _ in range(100)])))
# [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
Run Code Online (Sandbox Code Playgroud)


Ali*_*maz 9

我可以建议使用asyncio.BoundedSemaphore.

import asyncio

async def my_func(player, asyncio_semaphore):
    async with asyncio_semaphore:
        # do stuff

async def main():
    asyncio_semaphore = asyncio.BoundedSemaphore(200)
    jobs = []
    for i in range(12000):
        jobs.append(asyncio.ensure_future(my_func(players[i], asyncio_semaphore)))
    await asyncio.gather(*jobs)

if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.set_debug(True)
    loop.run_until_complete(main())
Run Code Online (Sandbox Code Playgroud)

这样,只有200个并发任务可以获取信号量并使用系统资源,而手头有12000个任务。

  • 请注意,您不需要 `BoundedSemaphore` - 普通的 `Semaphore(200)` 将具有相同的效果。`BoundedSemaphore` 有不同的用途 - 它被设计为与普通的 `Semaphore` 不同,它在信号量被释放_比被获取次数多时引发异常(而不是阻塞)。当它仅使用 `with` 获取/释放时,不会发生这种情况。 (12认同)