Получение asyncio для запуска функции по порядку (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))
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))