Python: дождаться завершения первого подпроцесса - PullRequest
3 голосов
/ 19 июня 2020

У меня есть список подпроцессов, я не общаюсь с ними и просто жду

Я хочу дождаться завершения первого процесса sh (это решение работает):

import subprocess

a = subprocess.Popen(['...'])

b = subprocess.Popen(['...'])


# wait for the first process to finish
while True:
    over = False
    for child in {a, b}:
        try:
            rst = child.wait(timeout=5)
        except subprocess.TimeoutExpired:
            continue  # this subprocess is still running

        if rst is not None:  # subprocess is no more running
            over = True
            break  # If either subprocess exits, so do we.
    if over:
        break


Я не хочу использовать os.wait (), потому что он может вернуться из другого подпроцесса, не входящего в список, который я жду.

Хорошее и элегантное решение, вероятно, будет с epoll или выберите и без l oop (пока верно)

Спасибо за помощь

Ответы [ 3 ]

1 голос
/ 19 июня 2020

Если вам не нужно получать выходные данные от процессов, Popen.poll() кажется самым простым способом проверить, выполнены ли они. Приведенный ниже while True l oop предназначен исключительно для демонстрационных целей: вы можете решить, как это сделать в вашей более крупной программе (например, выполнять проверку в отдельном потоке, выполнять проверку между другими работами программы и т. Д. c).

from subprocess import Popen
from time import sleep

ps = [
    Popen(['sleep', t])
    for t in ('3', '5', '2')
]

while True:
    exit_codes = [p.poll() for p in ps]
    print(exit_codes)
    if any(ec is not None for ec in exit_codes):
        break
    else:
        sleep(1)

Демо-вывод:

[None, None, None]
[None, None, None]
[None, None, 0]
1 голос
/ 19 июня 2020

Вот решение с использованием psutil - которое нацелено точно на этот вариант использования:

import subprocess
import psutil

a = subprocess.Popen(['/bin/sleep', "2"])

b = subprocess.Popen(['/bin/sleep', "4"])

procs_list = [psutil.Process(a.pid), psutil.Process(b.pid)]

def on_terminate(proc):
     print("process {} terminated".format(proc))

# waits for multiple processes to terminate
gone, alive = psutil.wait_procs(procs_list, timeout=3, callback=on_terminate)

Или, если вы хотите, чтобы al oop ждал одного выполняемого процесса:

while True: 
    gone, alive = psutil.wait_procs(procs_list, timeout=3, callback=on_terminate) 
    if len(gone)>0: 
        break
0 голосов
/ 19 июня 2020

Есть почти 2 способа сделать это: если вы хотите, чтобы команды блокировали и останавливали вашу программу до ее завершения, используйте subprocess.call

a = subprocess.call('...')
b = subprocess.call('...')

Я не думаю, что это то, что вам нужно.

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

```py
a = subprocess.Popen(['...'])

b = subprocess.Popen(['...'])

....
    for child in {a, b}:
        try:
            result, err = child.communicate(timeout=5)

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...