首先,我知道这看起来像是重复的。我一直在阅读:
Python subprocess readlines() hangs
Python Subprocess readline hangs() after reading all input
subprocess readline hangs waiting for EOF
但是这些选项要么直接不起作用,要么我不能使用它们。
问题
# Obviously, swap HOSTNAME1 and HOSTNAME2 with something real
cmd = "ssh -N -f -L 1111:<HOSTNAME1>:80 <HOSTNAME2>"
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=os.environ)
while True:
out = p.stdout.readline()
# Hangs here ^^^^^^^ forever
out = out.decode('utf-8')
if out:
print(out)
if p.poll() is not None:
break
我的困境是调用
subprocess.Popen()
的函数是一个运行bash命令的库函数,所以需要非常通用,并且有以下限制:signal.SIGALRM
出于与多处理相同的原因;父调用者可能试图设置自己的超时 readline()
调用在线程中,thread.join(timeout=1)
让程序继续,但是 ctrl+c 根本不起作用,并调用 sys.exit()
不退出程序,因为线程仍然打开。如您所知,您不能通过设计杀死python中的线程。 如果可以的话,我会有一个可行的解决方案杀死一个线程 ,但这是 super 禁忌,尽管这绝对是一个合法的用例。
我对任何想法持开放态度。
最佳答案
一种选择是使用线程发布到队列。然后你可以在队列中阻塞超时。您可以使阅读器线程成为守护程序,这样它就不会阻止系统退出。这是一个草图:
import subprocess
from threading import Thread
from queue import Queue
def reader(stream, queue):
while True:
line = stream.readline()
queue.put(line)
if not line:
break
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, ...)
queue = Queue()
thread = Thread(target=reader, args=(p.stdout, queue))
thread.daemon = True
thread.start()
while True:
out = queue.get(timeout=1) # timeout is optional
if not out: # Reached end of stream
break
... # Do whatever with output
# Output stream was closed but process may still be running
p.wait()
请注意,您应该根据您的特定用例调整此答案。例如,您可能希望添加一种方法来向读取器线程发出信号以在到达流的末尾之前停止运行。
另一种选择是轮询输入流,就像在这个问题中一样:timeout on subprocess readline in python
关于Python 子进程 readline() 挂起;不能使用普通选项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58471094/