首先,我知道这看起来像重复的。我一直在阅读:
Python subprocess readlines() hangs
Python Subprocess readline hangs() after reading all input
subprocess readline hangs waiting for EOF
但是这些选项要么直接不起作用,要么我不能使用它们。
# Obviously, swap URL1 and URL2 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中的线程。如果我可以杀死一个线程,我将有一个可行的解决方案,但这是超级禁忌,即使这绝对是合法的用例。
我愿意接受任何想法。
一种选择是使用线程发布到队列。然后,您可以超时超时阻塞队列。您可以使阅读器线程成为守护程序,这样就不会阻止系统退出。这是草图:
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, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=os.environ)
queue = Queue()
thread = Thread(target=reader, args=(p.stdout, queue), daemon=True)
thread.start()
while True:
out = queue.get(timeout=1)
out = out.decode('utf-8')
if out:
print(out)
if p.poll() is not None:
break
另一个选择是轮询输入流,例如在此问题中:timeout on subprocess readline in python