Я пытаюсь получить исключение из подпроцесса. Я могу получить его, если использую .communicate
, но я хотел бы избежать его использования, поскольку я передаю вывод из подпроцесса по мере его возникновения и не хочу ждать, пока весь подпроцесс завершится. Также предположим, что весь подпроцесс может занять очень много времени. Мне было интересно, как я могу поймать исключение, возникающее при потоковой передаче стандартного вывода из подпроцесса.
Рассмотрим приведенный ниже пример, поэтому я хотел бы, чтобы версия №1 работала, версия №2 вроде бы работает, но не хочу, чтобы это было так.
В main.py
import subprocess
class ExtProcess():
def __init__(self, *args):
self.proc = subprocess.Popen(['python', *args], stdout=subprocess.PIPE)
def __iter__(self):
return self
def __next__(self):
while True:
line = self.proc.stdout.readline()
if self.proc.returncode:
raise Exception("error here")
if not line:
raise StopIteration
return line
def run():
## version #1
reader = ExtProcess("sample_extproc.py")
for d in reader:
print(f"got: {d}")
## version #2
# proc = subprocess.Popen(['python', "sample_extproc.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# output, error = proc.communicate()
# print("got:", output)
# if proc.returncode:
# raise Exception(error)
def main():
try:
print("start...")
run()
print("complete...")
except Exception as e:
print(f"Package midstream error here: {str(e)}")
finally:
print("clean up...")
if __name__ == "__main__":
main()
В sample_extproc.py
for x in range(10):
print(x)
if x == 3:
raise RuntimeError("catch me")
Я хотел бы получить вывод, как показано ниже, из версии № 1:
start...
got: b'0\r\n'
got: b'1\r\n'
got: b'2\r\n'
got: b'3\r\n'
Package midstream error here: b'Traceback (most recent call last):\r\n File "sample_extproc.py", line 4, in <module>\r\n raise RuntimeError("catch me")\r\nRuntimeError: catch me\r\n'
clean up...
По сути, он перебирает стандартный вывод из подпроцесса, затем печатает исключение, когда оно возникает, а затем продолжает выполнять очистку.
returncode
, пока вы все еще читаете данные. Конечно, процесс может закрыть свой stdout перед выходом или несколько десятков байтов все еще будут находиться в FIFO во время выхода, но очень необычно, чтобы это занимало больше миллисекунд. , и даже тогда родительский процесс не будет знать статус выхода, пока он не вызовет системный вызовwait()
для его извлечения (при получении PID завершенного процесса из записи зомби, которую он оставляет в таблице процессов на время между вызовом выхода и его родительский процесс, читающий этот статус). - person Charles Duffy   schedule 14.10.2020p.wait()
, чтобы установитьp.returncode
. - person Charles Duffy   schedule 14.10.2020for line in proc.self.stdout:
, выходящего вp.wait()
, и проверкаp.returncode
, как толькоwait
вернется. - person Charles Duffy   schedule 14.10.2020