ASYNCIO。如何异步调用1000个方法并在它准备就绪后立即获得异步结果

时间:2017-12-20 09:46:20

标签: python python-3.x asynchronous async-await python-asyncio

我征求你的意见。我想在一个简单的例子中理解异步的工作。根据传说,你需要创建1000个返回一些结果的工人。但是你需要在准备好后立即归还它。 这是一个例子:

import asyncio


async def worker(number):
    print("worker # %d" % number)
    await asyncio.sleep(0)
    return str(number)


async def print_when_done(tasks):
    for res in asyncio.as_completed(tasks):
        print("Result worker %s" % await res)


coros = [worker(i) for i in range(10)]
loop = asyncio.get_event_loop()
loop.run_until_complete(print_when_done(coros))
loop.close()

问题是这个例子的工作结果不是同步的,它只是在不阻塞主进程的情况下调用函数,最后它返回所有函数的响应

worker # 2
worker # 3
worker # 4
worker # 1
worker # 0
Result worker 2
Result worker 3
Result worker 4
Result worker 1
Result worker 0

但如何以相似性实现结果:

worker # 2
worker # 3
worker # 4
Result worker 3
Result worker 2
worker # 1
Result worker 4
worker # 0
Result worker 1
Result worker 0

您可以创建一个ThreadPoolExecutor,或者ProcessPoolExecutor。但是,为什么你需要Asyncio,你可以创建没有它的线程并使用它们。

2 个答案:

答案 0 :(得分:3)

您正在寻找asyncio.wait

stopFyon
  

但是为什么你需要Asyncio,你可以创建没有它的线程并使用它们。

当然,线程可以更高效,你可以用它们做更多的事情,但单线程异步协作多任务更容易协调。

答案 1 :(得分:1)

  

它只是调用函数而不阻塞主进程,并且在   最后它返回所有函数的响应

它同时启动所有工作程序,它应该是这样,立即计算它们的结果(因为worker不包含任何实际的I / O阻塞)并同时返回结果。

如果你想看到工人在不同的时间返回结果,你应该让他们执行不同的时间 - 例如,通过放置await asyncio.sleep(randint(1, 3))而不是你的0睡眠。

我不确定我理解你为什么要这样:

worker # 2
worker # 3
worker # 4
Result worker 3

由于您在每个工作者的顶部都有print(之前没有一些I / O阻止操作)并且同时运行所有工作程序 - 您会在任何结果之前立即看到所有工作人员打印。

我的随机猜测是你可能想要限制并行运行的工人数量?在这种情况下,您可以使用asyncio.Semaphore等同步原语。

以下示例包含以上所有内容:

import asyncio
from random import randint

sem = asyncio.Semaphore(3)  # don't allow more then 3 workers parallely


async def worker(number):
    async with sem:
        print("started # %d" % number)
        await asyncio.sleep(randint(1, 3))
        return str(number)


async def main():
    coros = [worker(i) for i in range(10)]

    for res in asyncio.as_completed(coros):
        print("finished %s" % await res)


if __name__ ==  '__main__':
    loop = asyncio.get_event_loop()
    try:
        loop.run_until_complete(main())
    finally:
        loop.run_until_complete(loop.shutdown_asyncgens())
        loop.close()

输出:

started # 0
started # 6
started # 7
started # 2
finished 7
started # 8
finished 0
started # 3
finished 6
started # 9
finished 2
started # 4
finished 8
started # 1
started # 5
finished 3
finished 9
finished 4
finished 1
finished 5