subprocess.wait () не ожидает завершения процесса Popen (при использовании потоков)? - PullRequest
17 голосов
/ 14 июня 2011

У меня возникают некоторые проблемы при использовании subprocess.Popen() для порождения нескольких экземпляров одного и того же приложения из моего скрипта python, использующего потоки для их одновременной работы. В каждом потоке я запускаю приложение с помощью вызова popen(), а затем жду его завершения, вызывая wait(). Кажется, проблема в том, что wait() -all фактически не ждет завершения процесса. Я экспериментировал, используя только один поток и распечатывая текстовые сообщения, когда процесс начинается и когда он заканчивается. Таким образом, функция потока будет выглядеть примерно так:

def worker():
    while True:
        job = q.get() # q is a global Queue of jobs
        print('Starting process %d' % job['id'])
        proc = subprocess.Popen(job['cmd'], shell=True)
        proc.wait()
        print('Finished process %d' % job['id'])
        job.task_done()

Но даже если я использую только один поток, он напечатает несколько сообщений «Запуск процесса ...», прежде чем появится сообщение «Завершенный процесс ...». Есть ли случаи, когда wait() на самом деле не ждет? У меня есть несколько различных внешних приложений (консольные приложения C ++), в которых, в свою очередь, будет запущено несколько экземпляров одновременно, и для некоторых из них мой код работает, а для других - нет. Может ли быть проблема с внешними приложениями, которая как-то влияет на вызов wait()? Код для создания потоков выглядит примерно так:

for i in range(1):
    t = Thread(target=worker)
    t.daemon = True
    t.start()
q.join() # Wait for the queue to empty

Обновление 1 : Я также должен добавить, что для некоторых внешних приложений я иногда получаю код возврата (proc.returncode) -1073471801. Например, одно из внешних приложений выдаст этот код возврата первые два раза, когда вызывается Popen, но не последние два (когда у меня четыре задания).

Обновление 2 : Чтобы прояснить ситуацию, сейчас у меня в очереди четыре задания, то есть четыре разных тестовых случая. Когда я запускаю свой код, для одного из внешних приложений первые два Popen -вызова генерируют код возврата -1073471801. Но если я распечатываю точную команду, которую Popen вызывает, и запускаю ее в командном окне, она выполняется без проблем.

Решено! Мне удалось решить проблемы, которые у меня были. Я думаю, что проблема была в моем отсутствии опыта в многопоточном программировании. Я упустил тот факт, что когда я создавал свои первые рабочие потоки, они продолжали жить до тех пор, пока не завершится сценарий python. По ошибке я создавал больше рабочих потоков каждый раз, когда помещал новые элементы в очередь (я делаю это партиями для каждой внешней программы, которую я хочу запустить). Так что к тому времени, когда я добрался до четвертого внешнего приложения, у меня было запущено четыре потока одновременно, хотя я только думал, что у меня есть один.

Ответы [ 4 ]

13 голосов
/ 27 ноября 2012

Вы также можете использовать check_call() вместо Popen.check_call() ожидает завершения команды, даже если shell=True, а затем возвращает код завершения задания.

9 голосов
/ 14 июня 2011

К сожалению, при запуске подпроцесса с использованием shell=True, wait() будет ожидать только завершения подпроцесса sh, а не команды cmd.

Я предложу, если возможно, не использовать shell=True, если это невозможно, вы можете создать группу процессов, как в этом ответе , и использовать os.waitpid для дождитесь группы процессов, а не только процесса оболочки.

Надеюсь, это было полезно:)

0 голосов
/ 14 декабря 2016

У меня тоже были проблемы, но я был вдохновлен вашими.

Моя выглядит так и прекрасно работает:

    startupinfo = subprocess.STARTUPINFO()
    startupinfo.dwFlags = subprocess.STARTF_USESHOWWINDOW
    startupinfo.wShowWindow = subprocess.SW_HIDE
    proc = subprocess.Popen(command, startupinfo=startupinfo)
    proc.communicate()
    proc.wait()

Обратите внимание, что этот экран также скрывает окно.

0 голосов
/ 14 июня 2011

Убедитесь, что все приложения, которые вы вызываете, имеют действительные коды возврата системы после завершения

...