python connect () зависает после завершения процесса () - PullRequest
0 голосов
/ 25 февраля 2020

Приведенный ниже код пытается запустить несколько команд параллельно, и у каждой команды есть тайм-аут. Если обработка не завершена по таймауту, она должна быть остановлена ​​(я использую terminate ()).

Проблема заключается в том, что после завершения (код возврата установлен в -ve), метод connect () зависает и при принудительном выходе (Ctrl + C), затем отображается следующая ошибка.

(stdout, stderr) = proc.communicate()
File "python3.7/subprocess.py", line 926, in communicate
stdout = self.stdout.read()

Код

procList = []
for app in appList:
    try:
        p = subprocess.Popen(app['command'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
        procList.append((app, p))
    except Exception as e:
        print(e)

start = time.time()
while len(procList):
    time.sleep(30)
    try:
        for app, proc in procList:
            if (time.time() - start > app['timeoutSec']):
                proc.terminate()
            if proc.poll() is not None and app['mailSent'] == 0:
                (stdout, stderr) = proc.communicate() #Hangs here is the process is terminated
                send_results_mail('Execution Completed or Terminated')
                app['mailSent'] = 1
    except subprocess.SubprocessError as e:
        print(e)
    procList = [(app, proc) for (app, proc) in procList if app['mailSent'] == 0]

Ответы [ 2 ]

0 голосов
/ 27 февраля 2020

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

Поэтому мне пришлось рекурсивно завершать процессы, и для этого Я использовал решение, используя psutil

Пожалуйста, смотрите пост ниже для деталей

{ ссылка }

, как только все дочерние процессы и процессы внуков kill communicate() работает отлично.

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

0 голосов
/ 25 февраля 2020

РЕДАКТИРОВАТЬ: Вот рабочий пример, использующий kill (), с неправильно работающим ребенком (который не отвечает на terminate ()), но я не уверен в природе вашего дочернего процесса. Надеюсь, это поможет вам найти решение!

Простая дочерняя программа, Python 3:

import signal
import time

def sighandler(signal, _stack):
    print(f"Ignoring signal {signal}")

signal.signal(signal.SIGTERM, sighandler)
signal.signal(signal.SIGINT, sighandler)

secs = 10
print(f"Sleeping {secs} seconds...")
time.sleep(secs)
print("Exiting...")

Пересмотренная родительская программа, Python 3:

import subprocess
import time

start = time.time()
appList = [
   {'command': 'python ./child.py', 'timeoutSec': 2, 'mailSent': 0},
   {'command': 'python ./child.py', 'timeoutSec': 2, 'mailSent': 0},
   {'command': 'python ./child.py', 'timeoutSec': 2, 'mailSent': 0},
]

def logmsg(msg):
    elap = time.time()-start
    print(f"{elap:2.1f} secs: {msg}")

def send_results_mail(result):
    logmsg(f"Result: {result}")

procList = []
for app in appList:
    try:
        p = subprocess.Popen(app['command'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
        procList.append((app, p))
    except Exception as e:
        logmsg(e)
    logmsg(f"Launching child... {p.pid}")

start = time.time()
while len(procList):
    time.sleep(1)
    try:
        for app, proc in procList:
            if (time.time() - start > app['timeoutSec']):
                logmsg(f"Trying to terminate()...{proc.pid}")
                proc.terminate()
                proc.kill()
            if proc.poll() is not None and app['mailSent'] == 0:
                proc.kill()
                logmsg(f"Trying to communicate()...{proc.pid}")
                (stdout, stderr) = proc.communicate()
                send_results_mail('Execution Completed or Terminated')
                app['mailSent'] = 1
    except subprocess.SubprocessError as e:
        logmsg(e)
    procList = [(app, proc) for (app, proc) in procList if app['mailSent'] == 0]

Вывод:

$ python parent.py
0.0 secs: Launching child... 537567
0.0 secs: Launching child... 537568
0.0 secs: Launching child... 537569
2.0 secs: Trying to terminate()...537567
2.0 secs: Trying to terminate()...537568
2.0 secs: Trying to terminate()...537569
3.0 secs: Trying to terminate()...537567
3.0 secs: Trying to communicate()...537567
3.0 secs: Result: Execution Completed or Terminated
3.0 secs: Trying to terminate()...537568
3.0 secs: Trying to communicate()...537568
3.0 secs: Result: Execution Completed or Terminated
3.0 secs: Trying to terminate()...537569
3.0 secs: Trying to communicate()...537569
3.0 secs: Result: Execution Completed or Terminated
...