Python input () блокирует выполнение подпроцессов - PullRequest
0 голосов
/ 08 января 2020

У меня есть Python скрипт, который принимает пользовательский ввод. Различные пользовательские входы запускают разные функции. Рассматриваемая функциональность - это та, которая порождает несколько процессов. Вот сценарий: main.py.

import time
import threading
import concurrent.futures as cf


def executeparallelprocesses():

    numprocesses = 2
    durationseconds = 10

    futures = []

    print('Submit jobs as new processes.')
    with cf.ProcessPoolExecutor(max_workers=numprocesses) as executor:
        for i in range(numprocesses):
            futures.append(executor.submit(workcpu, 500, durationseconds))
            print('job submitted')
        print('all jobs submitted')

        print('Wait for jobs to complete.', flush=True)
        for future in cf.as_completed(futures):
            future.result()

        print('All jobs done.', flush=True)


def workcpu(x, durationseconds):
    print('Job executing in new process.')
    start = time.time()
    while time.time() - start < durationseconds:
        x * x


def main():

    while True:
        cmd = input('Press ENTER\n')
        if cmd == 'q':
            break
        thread = threading.Thread(target=executeparallelprocesses)
        thread.start()

    time.sleep(15)


if __name__ == '__main__':
    main()

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

(terminal prompt $) python3 main.py
Press ENTER

Submit jobs as new processes.
Press ENTER
job submitted
job submitted
all jobs submitted
Wait for jobs to complete.
Job executing in new process.
Job executing in new process.
All jobs done.
q
(terminal prompt $)

ПРОБЛЕМА: Когда сценарий вызывается из другой программы, подпроцессы не выполняются. Вот сценарий драйвера, driver.py:

import time
import subprocess
from subprocess import PIPE


args = ['python3', 'main.py']

p = subprocess.Popen(args, bufsize=0, stdin=PIPE, universal_newlines=True)

time.sleep(1)

print('', file=p.stdin, flush=True)

time.sleep(1)

print('q', file=p.stdin, flush=True)

time.sleep(20)

Обратите внимание, как «Задание выполняется в новом процессе». отсутствует в выходных данных следующего примера:

(terminal prompt $) python3 driver.py
Press ENTER
Submit jobs as new processes.
Press ENTER
job submitted
job submitted
all jobs submitted
Wait for jobs to complete.
(terminal prompt $)

Кажется, что оператор cmd = input('Press ENTER\n') в main.py блокирует и препятствует выполнению подпроцессов. Странно, но комментирование второго оператора time.sleep(1) в driver.py вызывает появление подпроцессов main.py, как и ожидалось. Еще один способ сделать эту «работу» - добавить time.sleep(1) внутри l oop из main.py сразу после thread.start().

. Этот чувствительный ко времени код хрупок. Есть ли надежный способ сделать это?

Ответы [ 2 ]

0 голосов
/ 09 января 2020

Я попробовал предложение ShadowRanger добавить вызов к multiprocessing.set_start_method():

if __name__ == '__main__':
    multiprocessing.set_start_method('spawn')
    main()

Это решило проблему для меня. Я прочитаю документацию , чтобы узнать больше об этом.

0 голосов
/ 08 января 2020

Проблема заключается в том, как вы пытаетесь установить связь со вторым сценарием, используя stdin=PIPE - попробуйте следующее для второго сценария:

import time
import subprocess
from subprocess import PIPE


args = ['python', 'junk.py']

p = subprocess.Popen(args, bufsize=0, stdin=PIPE, universal_newlines=True)

p.communicate(input='\nq\n')

time.sleep(20)

Вывод:

Press ENTER
Submit jobs as new processes.
Press ENTER
job submitted
job submitted
all jobs submitted
Wait for jobs to complete.
Job executing in new process.
Job executing in new process.
All jobs done.

Process finished with exit code 0

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

...