> 백엔드 개발 > 파이썬 튜토리얼 > Ruby 스크립트에서 읽을 때 `readline()`이 있는 `subprocess.Popen`이 정지되는 이유는 무엇이며 이 문제를 어떻게 해결할 수 있습니까?

Ruby 스크립트에서 읽을 때 `readline()`이 있는 `subprocess.Popen`이 정지되는 이유는 무엇이며 이 문제를 어떻게 해결할 수 있습니까?

Susan Sarandon
풀어 주다: 2024-12-19 05:44:08
원래의
375명이 탐색했습니다.

Why does `subprocess.Popen` with `readline()` hang when reading from a Ruby script, and how can this be fixed?

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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿