Получение asyncio для запуска функции по порядку (Python 3) - PullRequest
0 голосов
/ 24 апреля 2018

Вот простой пример использования 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 Ответ

0 голосов
/ 24 апреля 2018

Что происходит в вашем коде сейчас?

Вы создаете список сопрограмм (futures), каждый из которых будет запускать echo в пуле потоков, а затем запускаете их все сразу (await asyncio.wait(futures)).Поскольку одновременно выполняется несколько echo, и каждый из них печатается при запуске, все эти распечатки могут произойти в любое время.

Что вы хотите сделать?

Возможно, вы на самом деле не хотитечтобы запускать сопрограммы по порядку (в противном случае вы можете просто вызывать их в цикле без asyncio), вы хотите запустить их в пуле потоков одновременно, но распечатать их результаты в порядке создания сопрограмм

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

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

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

  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))
...