让 asyncio 按顺序运行函数(Python 3)

Posted

技术标签:

【中文标题】让 asyncio 按顺序运行函数(Python 3)【英文标题】:Getting asyncio to run a function in order (Python 3) 【发布时间】:2018-04-24 14:15:09 【问题描述】:

这是一个使用asyncio 打印从0 到9 的数字的简单示例。

问题:有时代码会打印出从 0 到 7 的数字,然后打印 9,然后是 8。尤其是当您将 ThreadPoolExecutor 设置为较小的数字(例如 4 或 5)时。

0
1
2
3
4
5
6
7
9
8

你如何让它总是按从 0 到 9 的顺序打印?为什么没有按顺序打印?

0
1
2
3
4
5
6
7
8
9

代码

import asyncio
from concurrent.futures import ThreadPoolExecutor


async def printThreaded(THREAD_POOL, length):   
    loop = asyncio.get_event_loop()
    futures = []
    for i in range(length):
        futures.append(loop.run_in_executor(THREAD_POOL, echo, i))
    await asyncio.wait(futures)


def echo(i):
    print(i)


THREAD_POOL = ThreadPoolExecutor(16)
with THREAD_POOL:
    loop = asyncio.get_event_loop()
    length = 10
    loop.run_until_complete(printThreaded(THREAD_POOL, length))

【问题讨论】:

Possible duplicate? 【参考方案1】:

你的代码现在发生了什么?

您创建的协程列表 (futures) 将在线程池中运行 echo,而不是一次启动它们 (await asyncio.wait(futures))。由于多个echo同时运行并且每个打印都在运行,所有这些打印都可以随时发生。

你想做什么?

你可能真的不想按顺序运行协程(否则你可以在没有asyncio的情况下循环调用它),你想在线程池中同时运行它们,但是按协程的顺序打印它们的结果已创建

在这种情况下,您应该:

    将线程中发生的实际工作从 打印出来

    可能更喜欢使用asyncio.gather来按顺序获取计算结果

    最后打印你在主线程中得到的有序结果

总结

这是上面解释过的代码的修改版本:

import time
from random import randint

import asyncio
from concurrent.futures import ThreadPoolExecutor


async def printThreaded(THREAD_POOL, length):   
    loop = asyncio.get_event_loop()

    # compute concurrently:
    coroutines = []
    for i in range(length):
        coroutine = loop.run_in_executor(THREAD_POOL, get_result, i)
        coroutines.append(coroutine)
    results = await asyncio.gather(*coroutines)

    # print ordered results:
    for res in results:
        print(res)



def get_result(i):

    time.sleep(randint(0, 2))  # actual work, reason you delegate 'get_result' function to threaed

    return i  # compute and return, but not print yet


THREAD_POOL = ThreadPoolExecutor(4)
with THREAD_POOL:
    loop = asyncio.get_event_loop()
    length = 10
    loop.run_until_complete(printThreaded(THREAD_POOL, length))

【讨论】:

以上是关于让 asyncio 按顺序运行函数(Python 3)的主要内容,如果未能解决你的问题,请参考以下文章

Python - 在 asyncio 中运行函数的正确方法是啥?

[Python 多线程] asyncio (十六)

学习 asyncio:异步运行一个有延迟的函数

如何使用 python 的 asyncio 模块正确创建和运行并发任务?

Python 的 asyncio.gather() 似乎没有异步运行任务

corroutine RuntimeError中的Asyncio:没有正在运行的事件循环