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

时间:2018-05-12 17:14:07

标签: 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`

players属于list类型,包含许多元素(例如12000)。它需要如此多的计算资源才能在asyncio.gather(*p)中同时运行所有这些资源,所以我宁愿同时运行的玩家数量为200.一旦达到199,我希望另一个协程开始执行。

这是否可以在asyncio中使用?

3 个答案:

答案 0 :(得分:2)

我建议使用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())

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

答案 1 :(得分:2)

您可能需要考虑将aiostream.stream.maptask_limit参数一起使用:

from aiostream import stream, pipe

async def main():
    xs = stream.iterate(players)
    ys = stream.map(xs, my_func, task_limit=100)
    zs = stream.list(ys)
    results = await zs

使用管道的方法相同:

async def main():
    results = await (
        stream.iterate(players) | 
        pipe.map(my_func, task_limit=100) |
        pipe.list())

有关详细信息,请参阅aiostream project pagedocumentation

免责声明:我是项目维护者。

答案 2 :(得分:0)

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

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]