Добавление результатов пула в словарь

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

Я могу объединить это и получить все результаты в виде списка, который затем я могу вставить в словарь один за другим, но это кажется неэффективным. Есть ли способ получить результаты по завершении каждого задания и напрямую добавить их в словарь?

По сути, у меня есть код ниже:

all_solutions = {}
for start, goal in itertools.combinations(graph, 2):
    all_solutions[(start, goal)] = search(graph, start, goal)

Я пытаюсь распараллелить это следующим образом:

all_solutions = {}
manager = multiprocessing.Manager()
graph_pool = manager.dict(graph)
pool = multiprocessing.Pool()
results = pool.starmap(search, zip(itertools.repeat(graph_pool),
                                   itertools.combinations(graph, 2)))
for i, start_goal in enumerate(itertools.combinations(graph, 2)):
    start, goal = start_goal[0], start_goal[1]
    all_solutions[(start, goal)] = results[i]

Что на самом деле работает, но повторяется дважды, один раз в пуле и один раз для записи в dict (не говоря уже о неуклюжей распаковке кортежа).


person Teknophilia    schedule 14.02.2018    source источник
comment
К вашему сведению, неуклюжая распаковка кортежа не требуется. Вам просто нужно больше круглых скобок: for i, (start, goal) in enumerate(itertools.combinations(graph, 2)): распаковывается непосредственно в start и goal (круглые скобки не необязательны в этом случае, потому что они нужны, чтобы было ясно, что происходит вложенная распаковка).   -  person ShadowRanger    schedule 14.02.2018
comment
@ShadowRanger, приятно знать; Благодарность!   -  person Teknophilia    schedule 14.02.2018


Ответы (1)


Это возможно, вам просто нужно переключиться на использование функции ленивого отображения (не map или starmap, которые должны закончить вычисление всех результатов, прежде чем вы сможете начать использовать любой из них):

from functools import partial
from itertools import tee

manager = multiprocessing.Manager()
graph_pool = manager.dict(graph)
pool = multiprocessing.Pool()

# Since you're processing in order and in parallel, tee might help a little
# by only generating the dict keys/search arguments once. That said, 
# combinations of n choose 2 are fairly cheap; the overhead of tee's caching
# might overwhelm the cost of just generating the combinations twice
startgoals1, startgoals2 = tee(itertools.combinations(graph, 2))

# Use partial binding of search with graph_pool to be able to use imap
# without a wrapper function; using imap lets us consume results as they become
# available, so the tee-ed generators don't store too many temporaries
results = pool.imap(partial(search, graph_pool), startgoals2))

# Efficiently create the dict from the start/goal pairs and the results of the search
# This line is eager, so it won't complete until all the results are generated, but
# it will be consuming the results as they become available in parallel with
# calculating the results
all_solutions = dict(zip(startgoals1, results))
person ShadowRanger    schedule 14.02.2018
comment
Вау, это точно. частично это именно то, что я искал, спасибо! - person Teknophilia; 14.02.2018
comment
@Технофилия: Яр. Предупреждение: partial будет работать медленно, если связанные аргументы дороги для pickle. В данном случае это управляемый dict, предназначенный для multiprocessing, поэтому стоимость травления — это просто информация, необходимая для повторного подключения к менеджеру (достаточно дешево), без копирования всех данных, но если аргументы большие/дорогие для травления, partial не подходит. Мой ответ на этот вопрос объясняет, почему в таком случае лучше использовать глобальную функцию-оболочку с аргументами по умолчанию. - person ShadowRanger; 14.02.2018
comment
спасибо за наводку. Сам управляемый dict довольно большой, но, если я правильно понимаю, он просто переподключается, а не дублируется, так что это не должно быть проблемой. Я читаю об этом, и ваш ответ очень помогает в понимании. - person Teknophilia; 14.02.2018