Python子进程readline()挂起;不能使用普通选项

问题描述 投票:1回答:1

首先,我知道这看起来像重复的。我一直在阅读:

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命令的库函数,因此它必须非常通用,并具有以下限制:

  • 必须显示输入的内容;不要阻止然后立即将所有垃圾内容发送给屏幕]
  • 如果父调用者对库函数进行多处理,则不能使用多处理(Python不允许子进程具有子进程)
  • 出于与多重处理相同的原因,无法使用signal.SIGALRM;父级呼叫者可能正在尝试设置自己的超时时间
  • 不能使用第三方非内置模块
  • 直接向上穿线不起作用。当readline()调用在线程中时,thread.join(timeout=1)让程序继续运行,但是ctrl + c根本无法在其上运行,并且调用sys.exit()不会退出程序,因为线程仍处于打开状态。如您所知,您无法通过设计杀死python中的线程。
  • [bufsize或其他子过程args似乎没有什么区别;也没有将readline()放在迭代器中。

如果我可以杀死一个线程,我将有一个可行的解决方案,但这是超级禁忌,即使这绝对是合法的用例。

我愿意接受任何想法。

python multithreading subprocess
1个回答
1
投票

一种选择是使用线程发布到队列。然后,您可以超时超时阻塞队列。您可以使阅读器线程成为守护程序,这样就不会阻止系统退出。这是草图:

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

© www.soinside.com 2019 - 2024. All rights reserved.