让 asyncio 按顺序 运行 一个函数 (Python 3)
Getting asyncio to run a function in order (Python 3)
这里是一个使用 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))
现在您的代码中发生了什么?
您创建协程列表 (futures
),每个 运行 echo
在线程池中,然后一次启动它们 (await asyncio.wait(futures)
)。由于同时有多个 echo
运行ning 并且每个打印都是 运行,所以所有这些打印都可以随时发生。
你想做什么?
你可能真的不想按顺序 运行 协同程序(否则你可以在没有 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
打印出 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))
现在您的代码中发生了什么?
您创建协程列表 (futures
),每个 运行 echo
在线程池中,然后一次启动它们 (await asyncio.wait(futures)
)。由于同时有多个 echo
运行ning 并且每个打印都是 运行,所以所有这些打印都可以随时发生。
你想做什么?
你可能真的不想按顺序 运行 协同程序(否则你可以在没有 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))