Получение 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), вы хотите запускать их в пуле потоков одновременно, но печатать их результаты в порядке создания сопрограмм

В этом случае вам следует:

  1. разделить фактическую работу, которая будет происходить в потоке от его печати

  2. вероятно, предпочитаете использовать asyncio.gather, чтобы получить вычисленные результаты в порядке

  3. наконец распечатать заказанные результаты, которые вы получили в основной теме

Резюме

Вот модифицированная версия вашего кода, которая объясняется выше:

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))
Другие вопросы по тегам