Как распечатать результаты Python ThreadPoolExecutor.map сразу?

Я запускаю функцию для нескольких наборов итераций, возвращая список всех результатов, как только все процессы завершены.

def fct(variable1, variable2):

   # do an operation that does not necessarily take the same amount of
   # time for different input variables and yields result1 and result2

   return result1, result2

variables1 = [1,2,3,4]
variables2 = [7,8,9,0]

with ThreadPoolExecutor(max_workers = 8) as executor:
    future = executor.map(fct,variables1,variables2)
    print '[%s]' % ', '.join(map(str, future))

>>> [ (12,3) , (13,4) , (14,5) , (15,6) ]

Как я могу напечатать промежуточные результаты, например, для variable1 = 1, variable2 = 7, как только их результаты будут вычислены?

2 ответа

Решение

map уже делает это, но join необходимо создать всю итерацию для создания объединенной строки. Меняя это на for Цикл позволит вам распечатать его постепенно:

for i in executor.map(fct, v1, v2):
    print(str(i))

Сохранение того же вывода, что и join код немного больше работы, но выполнимо независимо от:

first = True
print("[ ", end="")
for i in executor.map(fct, v1, v2):
    if first:
        first = False
    else:
        print(" , ", end="")

    print(str(i), end="")
print("]", end="")

Если вы хотите использовать результаты по мере их завершения, не сохраняя порядок исходной итерации, вы можете использовать executor.submit вместе с concurrent.futures.as_completed:

from concurrent.futures import ThreadPoolExecutor, as_completed
import time
import random

def fct(variable1, variable2):
   time.sleep(random.randint(1,5))
   return variable1+1, variable2+1

variables1 = [1,2,3,4]
variables2 = [7,8,9,0]

with ThreadPoolExecutor(max_workers = 8) as executor:
    for out in as_completed([executor.submit(fct,*vars) 
                                for vars in zip(variables1, variables2)]):
        print(out.result())

Вывод (хотя любой заказ возможен на любом заданном прогоне, из-за random.randint):

(4, 10)
(5, 1)
(2, 8)
(3, 9)

as_completed даст Future из его списка ввода, как только это Future помечается как выполненное, независимо от того, где оно фактически находится в списке ввода. Таким образом, если второй элемент выполняется через 2 секунды, а первый занимает пятнадцать, вы увидите результат второго элемента через две секунды, вместо того, чтобы ждать пятнадцать. Это может или не может быть желательным поведением, в зависимости от вашего конкретного случая использования.

Редактировать:

Обратите внимание, что таким образом вы все равно можете получить вывод в оригинальном порядке. Вам просто нужно сохранить список, который вы даете as_completed:

with ThreadPoolExecutor(max_workers = 8) as executor:
    jobs = [executor.submit(fct, *vars) 
               for vars in zip(variables1, variables2)]

    for out in as_completed(jobs):
        print(out.result())
    results = [r.result() for r in jobs]
    print(results)

Выход:

(5, 1)
(2, 8)
(3, 9)
(4, 10)
[(2, 8), (3, 9), (4, 10), (5, 1)]
Другие вопросы по тегам