如何避免 Python 程序在读取进程输出时挂起?

Susan Sarandon
发布: 2024-11-02 13:54:29
原创
428 人浏览过

How to Avoid Python Programs from Hanging When Reading Process Output?

停止读取 Python 中的进程输出而不挂起?

问题:

Python 程序需要与外部交互连续产生输出的过程(例如“顶部”)。但是,直接读取输出可能会导致程序无限期挂起。

解决方案:

为了防止挂起,必须在以下情况下采用非阻塞或异步机制:读取过程输出。以下是一些可能的方法:

假脱机临时文件(推荐)

此方法利用专用文件对象来存储进程输出。

#! /usr/bin/env python<br>导入子进程<br>导入临时文件<br>导入时间<p>def main():</p><pre class="brush:php;toolbar:false"># Open a temporary file (automatically deleted on closure)
f = tempfile.TemporaryFile()

# Start the process and redirect stdout to the file
p = subprocess.Popen(["top"], stdout=f)

# Wait for a specified duration
time.sleep(2)

# Kill the process
p.terminate()
p.wait()

# Rewind and read the captured output from the file
f.seek(0)
output = f.read()

# Print the output
print(output)
f.close()
登录后复制

if 名称 == "__main__":

main()
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

基于线程的输出读取

这种方法采用单独的线程来连续读取进程输出,同时主线程继续执行其他任务。

导入集合<br>导入子进程<br>导入线程<br>导入时间</p><p>def read_output(process,append):</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">for line in iter(process.stdout.readline, ""):
    append(line)
登录后复制

def main():

# Start the process and redirect stdout
process = subprocess.Popen(["top"], stdout=subprocess.PIPE, close_fds=True)

# Create a thread for output reading
q = collections.deque(maxlen=200)
t = threading.Thread(target=read_output, args=(process, q.append))
t.daemon = True
t.start()

# Wait for the specified duration
time.sleep(2)

# Print the saved output
print(''.join(q))
登录后复制

if 名称 == "__main__":

main()
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

signal.alarm()(仅限 Unix)

此方法使用 Unix 信号在指定超时后终止进程,无论是否已读取所有输出。

导入集合<br>导入信号<br>导入子进程</p><p>class Alarm(Exception):</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">pass
登录后复制

def Alarm_handler(signum,frame):

raise Alarm
登录后复制

def main():

# Start the process and redirect stdout
process = subprocess.Popen(["top"], stdout=subprocess.PIPE, close_fds=True)

# Set signal handler
signal.signal(signal.SIGALRM, alarm_handler)
signal.alarm(2)

try:
    # Read and save a specified number of lines
    q = collections.deque(maxlen=200)
    for line in iter(process.stdout.readline, ""):
        q.append(line)
    signal.alarm(0)  # Cancel alarm
except Alarm:
    process.terminate()
finally:
    # Print the saved output
    print(''.join(q))
登录后复制

if 名称 == "__main__":

main()
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

threading.Timer

此方法使用计时器在指定的超时后终止进程。它适用于 Unix 和 Windows 系统。

导入集合<br>导入子进程<br>导入线程</p><p>def main():</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false"># Start the process and redirect stdout
process = subprocess.Popen(["top"], stdout=subprocess.PIPE, close_fds=True)

# Create a timer for process termination
timer = threading.Timer(2, process.terminate)
timer.start()

# Read and save a specified number of lines
q = collections.deque(maxlen=200)
for line in iter(process.stdout.readline, ""):
    q.append(line)
timer.cancel()

# Print the saved output
print(''.join(q))
登录后复制

if name == "__main__":

main()
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

没有线程,没有信号

此方法使用简单的基于时间的循环,用于检查进程输出,如果超过指定超时则将其终止。

导入集合<br>导入子进程<br>导入系统<br>导入时间</p> <p>def main():</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">args = sys.argv[1:]
if not args:
    args = ['top']

# Start the process and redirect stdout
process = subprocess.Popen(args, stdout=subprocess.PIPE, close_fds=True)

# Save a specified number of lines
q = collections.deque(maxlen=200)

# Set a timeout duration
timeout = 2

now = start = time.time()
while (now - start) < timeout:
    line = process.stdout.readline()
    if not line:
        break
    q.append(line)
    now = time.time()
else:  # On timeout
    process.terminate()

# Print the saved output
print(''.join(q))
登录后复制

if 名称 == "__main__":

main()
登录后复制
登录后复制
登录后复制
登录后复制
登录后复制

注意:存储的行数可以根据需要通过设置deque数据结构的'maxlen'参数来调整。

以上是如何避免 Python 程序在读取进程输出时挂起?的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:php.cn
上一篇:能否让 Python 生成器对象焕然一新以供重用? 下一篇:使用 Pandas 导入 CSV 文件时如何跳过特定行?
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
最新问题
关于CSS思维导图的课件在哪? 课件
来自于 2024-04-16 10:10:18
0
0
1549
相关专题
更多>
热门推荐
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责声明 Sitemap
PHP中文网:公益在线PHP培训,帮助PHP学习者快速成长!