Python子进程readlines()挂起

我尝试完成的任务是流式处理ruby文件并打印输出。(注意:我不想一次打印出所有内容)

main.py

from subprocess import Popen, PIPE, STDOUT

import pty

import os

file_path = '/Users/luciano/Desktop/ruby_sleep.rb'

command = ' '.join(["ruby", file_path])

master, slave = pty.openpty()

proc = Popen(command, bufsize=0, shell=True, stdout=slave, stderr=slave, close_fds=True)

stdout = os.fdopen(master, 'r', 0)

while proc.poll() is None:

data = stdout.readline()

if data != "":

print(data)

else:

break

print("This is never reached!")

ruby_sleep.rb

sleep 2

puts "goodbye!"

问题

流文件工作正常。打招呼/再见输出将延迟2秒打印。就像脚本应该工作一样。问题是readline()最终挂起并且永不退出。我从来没有达到最后的打印。

我知道这里有很多类似的问题,但是这些都不是让我解决问题的方法。我并不是整个子流程中的人,所以请给我一个更实际的/具体的答案。

问候

编辑

修复意外的代码。(与实际错误无关)

回答:

我假设你pty是出于Q中概述的原因而使用的:为什么不仅仅使用管道(popen())?(到目前为止,所有其他答案都将忽略你的“注意:我不想一次打印所有内容”)。

pty仅在docs中说过是Linux :

由于伪终端处理高度依赖平台,因此有代码仅适用于Linux。(Linux代码应该可以在其他平台上运行,但尚未经过测试。)

目前尚不清楚它在其他操作系统上的运行情况。

你可以尝试pexpect:

import sys

import pexpect

pexpect.run("ruby ruby_sleep.rb", logfile=sys.stdout)

或stdbuf在非交互模式下启用行缓冲:

from subprocess import Popen, PIPE, STDOUT

proc = Popen(['stdbuf', '-oL', 'ruby', 'ruby_sleep.rb'],

bufsize=1, stdout=PIPE, stderr=STDOUT, close_fds=True)

for line in iter(proc.stdout.readline, b''):

print line,

proc.stdout.close()

proc.wait()

或者pty基于@Antti Haapala的答案从stdlib 使用:

#!/usr/bin/env python

import errno

import os

import pty

from subprocess import Popen, STDOUT

master_fd, slave_fd = pty.openpty() # provide tty to enable

# line-buffering on ruby's side

proc = Popen(['ruby', 'ruby_sleep.rb'],

stdin=slave_fd, stdout=slave_fd, stderr=STDOUT, close_fds=True)

os.close(slave_fd)

try:

while 1:

try:

data = os.read(master_fd, 512)

except OSError as e:

if e.errno != errno.EIO:

raise

break # EIO means EOF on some systems

else:

if not data: # EOF

break

print('got ' + repr(data))

finally:

os.close(master_fd)

if proc.poll() is None:

proc.kill()

proc.wait()

print("This is reached!")

这三个代码示例都立即打印“ hello”(在看到第一个EOL时)。

此处保留旧的更复杂的代码示例,因为可能会在SO的其他帖子中进行引用和讨论

或者使用pty基于@Antti Haapala的答案:

import os

import pty

import select

from subprocess import Popen, STDOUT

master_fd, slave_fd = pty.openpty() # provide tty to enable

# line-buffering on ruby's side

proc = Popen(['ruby', 'ruby_sleep.rb'],

stdout=slave_fd, stderr=STDOUT, close_fds=True)

timeout = .04 # seconds

while 1:

ready, _, _ = select.select([master_fd], [], [], timeout)

if ready:

data = os.read(master_fd, 512)

if not data:

break

print("got " + repr(data))

elif proc.poll() is not None: # select timeout

assert not select.select([master_fd], [], [], 0)[0] # detect race condition

break # proc exited

os.close(slave_fd) # can't do it sooner: it leads to errno.EIO error

os.close(master_fd)

proc.wait()

print("This is reached!")

以上是 Python子进程readlines()挂起 的全部内容, 来源链接: utcz.com/qa/416658.html

回到顶部