0

我想以非阻塞方式读取外部程序的输出与我的 python 代码同时运行。为了启动程序(例如 netcat),我使用 subprocess.Popen 并将其 stdout 和 stderr 绑定到 subprocess.PIPE。然后我启动一个 multiprocessing.Process ,它的任务是检查该程序是否仍在运行(proc.poll() ),如果是,它会尝试从其管道中读取。我的问题是“proc.poll()”在“listen_to_fds”函数中总是返回 0,但在“call”函数(这是主函数)中运行良好,即 proc.poll() 返回 None(应用程序我启动永远不会完成,所以这是正确的返回值)。

我用以下函数调用: call ("./test.sh")

我的模块

def listen_to_fds(logger,proc):
  while proc.poll() is None:
    print("program still running", proc.returncode)
    data = proc.stdout.read()
    if data:
        print("Data", data)
    time.sleep(1)

print("last check", proc.returncode )



def call(cli ):

logger = logging.getLogger("isix.daemon")
cli_args = shlex.split(cli)

proc = subprocess.Popen(
        cli_args
        ,stdout=subprocess.PIPE 
        ,stderr=subprocess.PIPE
        )


set_fd_as_nonblocking( proc.stdout )
set_fd_as_nonblocking( proc.stderr )

pipe2 = multiprocessing.Process( 
    target=listen_to_fds,
    args=( logger, proc )
    )
while proc.poll() is None:
   print("program still running", proc.returncode)
   data = proc.stdout.read()
   if data:
         print("Data", data)
   time.sleep(1)
4

1 回答 1

0

subprocesspoll函数使用操作系统的wait调用(通常在非阻塞模式下wait4),它要求执行“等待”的进程是正在等待的进程的父进程。

除了直接父级之外,您也无法在任何其他地方收集返回码,但您可以0通过发送信号(零)来检查任何进程的存在,使用os.kill. 如果您被允许发送信号,并且该进程存在,则os.kill(pid, 0)成功(不影响其他进程)。如果不允许您发送信号(该进程存在但属于另一个用户),os.kill(pid, 0)则引发一个OSErrorwithEPERM作为其errno. 如果该进程不再存在,则os.kill(pid, 0)引发一个OSErrorwithESRCH作为它的errno. (如果进程在您不查看时完成,则会出现“错误窗口”,然后该进程的父进程收集它,使进程 ID 可供重用,然后您的相同用户 ID 开始一个新的,获得相同进程 ID 的不相关进程——但进程 ID 不会被故意回收很快,因此不太可能。)

不过,总的来说,最好采用其他方法,例如使用selectorepoll或类似方法来决定何时读取数据。

于 2013-09-18T00:29:58.200 回答