Python subprocess.Popen 投票似乎挂起但沟通有效
Python subprocess.Popen poll seems to hang but communicate works
child = subprocess.Popen(command,
shell=True,
env=environment,
close_fds=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
stdin=sys.stdin,
preexec_fn=os.setsid
)
child_interrupted = False
while child.poll() is None:
if Signal.isInterrupted():
child_interrupted = True
os.killpg(os.getpgid(child.pid), signal.SIGTERM)
break
time.sleep(0.1)
subout = child.communicate()[0]
logging.info(subout)
以上适用于它执行的大多数命令 (90%) 但对于某些命令它会挂起
对于那些反复挂起的命令,如果我去掉下面的命令,它就可以正常工作:
child_interrupted = False
while child.poll() is None:
if Signal.isInterrupted():
child_interrupted = True
os.killpg(os.getpgid(child.pid), signal.SIGTERM)
break
time.sleep(0.1)
我假设那些挂起的命令,child.poll() is None
即使工作完成了??
communicate() 可以告诉进程已完成但 poll() 不能?
我已经在这些进程上执行了 ps -ef
并且它们仅在 child.poll()
代码到位时才失效
知道为什么吗?
看起来像 defunct 意味着 "That's a zombie process, it's finished but the parent hasn't wait()ed for it yet."
好吧,我正在轮询,看看我是否可以打电话给 wait/communitcate...
您已将 Popen
对象设置为通过管道接收子进程的 stdout
。问题是,在进程退出之前,您不会从该管道读取数据。如果该过程产生足够的输出来填充 OS 级别的管道缓冲区,并且您没有排空管道,那么您就会陷入僵局;子进程希望您读取其写入的输出,以便它可以继续写入,然后退出,而您正在等待它退出,然后再读取输出。
如果需要进行显式轮询和中断检查,解决此死锁的最简单方法可能是启动一个排空管道的线程:
... launch the thread just after Popen called ...
draineddata = []
# Trivial thread just reads lines from stdout into the list
drainerthread = threading.Thread(target=draineddata.extend, args=(child.stdout,))
drainerthread.daemon = True
drainerthread.start()
... then where you had been doing communicate, change it to: ...
child.wait()
drainerthread.join()
subout = b''.join(draineddata) # Combine the data read back to a single output
child = subprocess.Popen(command,
shell=True,
env=environment,
close_fds=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
stdin=sys.stdin,
preexec_fn=os.setsid
)
child_interrupted = False
while child.poll() is None:
if Signal.isInterrupted():
child_interrupted = True
os.killpg(os.getpgid(child.pid), signal.SIGTERM)
break
time.sleep(0.1)
subout = child.communicate()[0]
logging.info(subout)
以上适用于它执行的大多数命令 (90%) 但对于某些命令它会挂起
对于那些反复挂起的命令,如果我去掉下面的命令,它就可以正常工作:
child_interrupted = False
while child.poll() is None:
if Signal.isInterrupted():
child_interrupted = True
os.killpg(os.getpgid(child.pid), signal.SIGTERM)
break
time.sleep(0.1)
我假设那些挂起的命令,child.poll() is None
即使工作完成了??
communicate() 可以告诉进程已完成但 poll() 不能?
我已经在这些进程上执行了 ps -ef
并且它们仅在 child.poll()
代码到位时才失效
知道为什么吗?
看起来像 defunct 意味着 "That's a zombie process, it's finished but the parent hasn't wait()ed for it yet." 好吧,我正在轮询,看看我是否可以打电话给 wait/communitcate...
您已将 Popen
对象设置为通过管道接收子进程的 stdout
。问题是,在进程退出之前,您不会从该管道读取数据。如果该过程产生足够的输出来填充 OS 级别的管道缓冲区,并且您没有排空管道,那么您就会陷入僵局;子进程希望您读取其写入的输出,以便它可以继续写入,然后退出,而您正在等待它退出,然后再读取输出。
如果需要进行显式轮询和中断检查,解决此死锁的最简单方法可能是启动一个排空管道的线程:
... launch the thread just after Popen called ...
draineddata = []
# Trivial thread just reads lines from stdout into the list
drainerthread = threading.Thread(target=draineddata.extend, args=(child.stdout,))
drainerthread.daemon = True
drainerthread.start()
... then where you had been doing communicate, change it to: ...
child.wait()
drainerthread.join()
subout = b''.join(draineddata) # Combine the data read back to a single output