Как заставить две разные вещи происходить одновременно в Python? - PullRequest
1 голос
/ 06 марта 2020

Я привык к многопроцессорности, но теперь у меня проблема, когда mp.Pool не тот инструмент, который мне нужен.

У меня есть процесс, который подготавливает ввод, и другой процесс, который его использует. Я не использую все свои ядра, поэтому хочу иметь два go одновременно, причем первый готовит пакет для следующей итерации. Как мне это сделать? И (важно), как называется такая штука, чтобы я мог go и погуглить?

Вот глупый пример. Следующий код занимает 8 секунд:

import time
def make_input():
    time.sleep(1)
    return "cthulhu r'lyeh wgah'nagl fhtagn"

def make_output(input):
    time.sleep(1)
    return input.upper()

start = time.time()
for i in range(4):
    input = make_input()
    output = make_output(input)
    print(output)

print(time.time() - start)

CTHULHU R'LYEH WGAH'NAGL FHTAGN
CTHULHU R'LYEH WGAH'NAGL FHTAGN
CTHULHU R'LYEH WGAH'NAGL FHTAGN
CTHULHU R'LYEH WGAH'NAGL FHTAGN
8.018263101577759

Если бы я готовил пакеты ввода одновременно с выводом, это заняло бы четыре секунды. Примерно так:

next_input = make_input()
start = time.time()
for i in range(4):
    res = do_at_the_same_time(
        output = make_output(next_input),
        next_input = make_input()
    )
    print(output)

print(time.time() - start)

Но, очевидно, это не работает. Как я могу выполнить sh то, что я пытаюсь выполнить sh?

Важное примечание: я попробовал следующее, но это не удалось, потому что исполняющий работник работал в неправильной области (например, для моего фактический вариант использования). В моем фиктивном сценарии использования он не работает, потому что он печатает в другом процессе.

def proc(i):
    if i == 0:
        return make_input()
    if i == 1:
        return make_output(next_input)

next_input = make_input()
for i in range(4):
    pool = mp.Pool(2)
    next_input = pool.map(proc, [0, 1])[0]
    pool.close()

Поэтому мне нужно решение, в котором вторые процессы происходят в той же области или среде, что и для l oop, и где первый имеет вывод, который может быть получен из этой области.

1 Ответ

0 голосов
/ 06 марта 2020

Вы должны быть в состоянии использовать Pool. Если я правильно понимаю, вы хотите, чтобы один работник подготовил ввод для следующего работника, который запускает и делает с ним что-то большее, учитывая ваши примерные функции, это должно сделать именно это:

pool = mp.Pool(2)
for i in range(4):
    next_input = pool.apply(make_input)
    pool.apply_async(make_output, (next_input, ), callback=print)
pool.close()
pool.join()

Мы готовим пул с 2 работниками, теперь мы хотим запустить l oop, чтобы дважды запустить нашу пару задач.

Мы делегируем make_input работнику, используя apply() в ожидании функции чтобы завершить, присвойте результат next_input. Примечание: в этом примере мы могли бы использовать один рабочий пул и просто запустить next_input = make_input() (т.е. в том же процессе, в котором запускается ваш скрипт и просто делегировать make_output()).

Теперь более интересный бит: используя apply_async(), мы просим работника запустить make_output, передав ему один параметр next_input и сообщив ему runt (или любую функцию) print с результатом make_output как аргумент передан функции, зарегистрированной с callback.

Затем мы close() пул не принимает больше заданий и join() ждут, пока процессы завершат свои задания.

...