Home > Backend Development > Python Tutorial > Why Does Python's `subprocess.Popen` with `readlines()` Hang, and How Can I Fix It?

Why Does Python's `subprocess.Popen` with `readlines()` Hang, and How Can I Fix It?

DDD
Release: 2024-12-03 10:37:10
Original
142 people have browsed it

Why Does Python's `subprocess.Popen` with `readlines()` Hang, and How Can I Fix It?

Python subprocess readlines() Hangs Issue

Introduction

Streaming a file and printing output line by line can be achieved using various methods. However, utilizing subprocess with readlines() may lead to hang issues.

The Python Script

Consider the Python script "main.py" designed to stream a Ruby file "ruby_sleep.rb" and print its output.

import pty
import os
from subprocess import Popen, PIPE, STDOUT

file_path = '/path/to/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 line is never reached")
Copy after login

The Problem and Observations

Executing this script streams the Ruby output as expected, but the readline() method hangs indefinitely, resulting in the "This line is never reached" string never being printed.

Solution Approaches

Various solutions have been proposed to address this hang issue:

1. Utilizing Stdbuf

Stdbuf enables line-buffering in non-interactive mode.

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()
Copy after login

2. Employing Pexpect

Pexpect can be used for line-based control.

import pexpect

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

3. Using PTY

PTY allows for providing a tty to enable line-buffering on the Ruby side.

import os
import pty
from subprocess import Popen, STDOUT

master_fd, slave_fd = pty.openpty()
proc = Popen(['ruby', 'ruby_sleep.rb'],
             stdin=slave_fd, stdout=slave_fd, stderr=STDOUT, close_fds=True)
os.close(slave_fd)
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!")
Copy after login

The above is the detailed content of Why Does Python's `subprocess.Popen` with `readlines()` Hang, and How Can I Fix It?. For more information, please follow other related articles on the PHP Chinese website!

source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template