Python 하위 프로세스 readlines()가 중단됩니다
문제:
subprocess.Popen을 사용하여 Ruby 스크립트의 출력을 읽을 때 스트리밍 방식의 readline()과 readline()은 무기한으로 중단되며 절대 중단되지 않습니다.
배경:
Ruby 파일의 출력을 한 줄씩 스트리밍하여 전체 출력을 버퍼링하지 않고 인쇄하는 것이 목표입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 스크립트는 2초 길이의 간단한 메시지를 출력합니다. 지연:
1 2 3 4 5 | puts "hello"
sleep 2
puts "goodbye!"
|
로그인 후 복사
근본 원인:
ruby 스크립트가 줄을 종료하지 않고(즉, 개행 없이) 데이터를 출력하기 때문에 readline()이 계속 중단된 상태로 유지됩니다. 이로 인해 readline()은 개행 문자가 줄을 완료할 때까지 무기한 대기하게 됩니다.
해결책:
플랫폼 가용성에 따라 여러 가지 해결 방법이 있습니다.
-
Linux:
표준 라이브러리의 pty를 사용하여 의사 터미널(tty)을 열고 Ruby 측에서 줄 버퍼링을 활성화하여 각 줄이 줄바꿈으로 끝나도록 합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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!" )
|
로그인 후 복사
-
Linux 기반의 경우 플랫폼:
표준 라이브러리에서 pty를 사용하고 마스터 파일 설명자의 활동을 모니터링하도록 선택하여 데이터가 차단되지 않는 방식으로 읽혀지도록 합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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!" )
|
로그인 후 복사
-
크로스 플랫폼 옵션:
사용 stdbuf를 사용하면 비대화형 모드에서 라인 버퍼링을 활성화할 수 있습니다.
1 2 3 4 5 6 7 8 | 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()
|
로그인 후 복사
이러한 솔루션은 모두 Ruby 측에서 라인 버퍼링을 활성화하여 각 줄이 줄바꿈으로 끝나도록 하고 readline( ) 올바르게 작동하려면
위 내용은 Ruby 스크립트에서 읽을 때 `readline()`이 있는 `subprocess.Popen`이 정지되는 이유는 무엇이며 이 문제를 어떻게 해결할 수 있습니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!