从 python 中的管道子进程标准输出读取行时的内存使用情况

Memory usage when reading lines from a piped subprocess stdout in python

我只想了解 "background" 在处理 subprocess.Popen() 结果和逐行读取时的内存使用情况。这是一个简单的例子。

给定以下脚本 test.py 打印 "Hello" 然后等待 10 秒并打印 "world":

import sys
import time
print ("Hello")
sys.stdout.flush()
time.sleep(10)
print ("World")

然后下面的脚本test_sub.py将作为子进程'test.py'调用,将标准输出重定向到管道,然后逐行读取:

import subprocess, time, os, sy

cmd = ["python3","test.py"]

p = subprocess.Popen(cmd,
                     stdout=subprocess.PIPE,
                     stderr=subprocess.STDOUT, universal_newlines = True)

for line in iter(p.stdout.readline, ''):
   print("---" + line.rstrip())

在这种情况下,我的问题是,当我 运行 test_sub.py 执行子进程调用后,它将打印 "Hello" 然后等待 10 秒,直到 "world" 出现然后打印出来,在这 10 秒的等待期间 "Hello" 发生了什么?它是存储在内存中直到 test_sub.py 完成,还是在第一次迭代时被丢弃?

对于这个例子来说这可能无关紧要,但是当处理非常大的文件时它就很重要了。

what happens to "Hello" during those 10s of waiting?

"Hello"(在 parent 中)可通过 line 名称获得,直到 .readline() returns 第二次,即 "Hello"在 parent.

中读取 print("World") 的输出之前,至少 还活着

如果你的意思是在 child 过程中发生了什么,那么在 sys.stdout.flush() 之后 "Hello" object 没有理由继续存在,但它可能例如,看到Does Python intern strings?

Does it get stored in memory until test_sub.py finishes, or does it get tossed away in the first iteration?

第二次.readline()returns后,line指的是"World""Hello" 之后会发生什么取决于特定 Python 实现中的垃圾收集,即,即使 line"World"; object "Hello" 可能还会继续活一段时间。 Releasing memory in Python.

您可以使用 debug python 构建设置 PYTHONDUMPREFS=1 envvar 和 运行 您的代码,以查看 object当 python 进程退出时还活着。例如,考虑以下代码:

#!/usr/bin/env python3
import threading
import time
import sys

def strings():
    yield "hello"
    time.sleep(.5)
    yield "world"
    time.sleep(.5)

def print_line():
    while True:
        time.sleep(.1)
        print('+++', line, file=sys.stderr)

threading.Thread(target=print_line, daemon=True).start()
for line in strings():
    print('---', line)
time.sleep(1)

说明line直到第二个yield才反弹。 PYTHONDUMPREFS=1 ./python . |& grep "'hello'" 的输出 显示当 python 退出时 'hello' 仍然存在。