subprocess.Popen.communicate处理大数据集效率低吗?

0 投票
1 回答
525 浏览
提问于 2025-04-18 14:58

我明白 communicate() 这个函数会等进程完成后,才会把数据存储到内存中并返回。我在想下面的代码可能效率不高,因为我想查询所有有趣的 RPM(软件包),并收集每个 RPM 的信息。这涉及到大约 15 个 RPM 在一台服务器上,而我可能需要在一个组里处理多达 200 台服务器。

我想在 Linux 中查询 RPM 数据库,获取每个 .rpm 的信息并存储起来。

在 Linux 中,我会这样做:

rpm -qa --qf '%{NAME} %{VERSION} %{RELEASE}\n' | grep this

而且我可以使用 RPM 提供的所有 --queryformat 选项。

所以我在 Python 中有这个代码,它是可以工作的。但我想让它更简单。

def getrpms():
queryall = []
rpmqa = subprocess.Popen(['rpm', '-qa'], stdout=subprocess.PIPE,)
grep = subprocess.Popen(['grep', 'stuff'], stdin=rpmqa.stdout, stdout=subprocess.PIPE,)
sort = subprocess.Popen(['sort', '-r'], stdin=grep.stdout, stdout=subprocess.PIPE,)
end_of_pipe = sort.stdout

for line in end_of_pipe:
    queryall.append(line.strip())
return queryall

def rpminfo():
for rpm in getrpms():
    command = "rpm -qi {} ".format(rpm)
    args = shlex.split(command)
    p = subprocess.Popen(args, stdout=subprocess.PIPE)
    pl = p.communicate()    # returns a tuple
    print pl

我该如何提高效率呢?我看到可以使用线程和流,但我不知道该怎么做。

1 个回答

0

注意:读取的数据会暂时存储在内存中,所以如果数据量很大或者没有上限,就不要使用这种方法。

这里说的“很大”其实有点模糊,但一般来说是指几个兆字节,甚至更多。对于单个RPM来说,rpm -qi的输出应该远远达不到这个大小。所以在这里不需要担心效率问题。

另外,没有必要把命令行构建成一个完整的字符串再拆分。可以先构建一个列表:

p = subprocess.Popen(['rpm', '-qi', rpm, stdout=subprocess.PIPE)

为了避免在内存中构建一个包含所有匹配stuff的RPM的大列表,可以把getrpms()做成一个生成器。这样,你就不需要一次性读取子进程的所有文本行,而是可以逐行读取和处理。

def getrpms():
    rpmqa = subprocess.Popen(['rpm', '-qa'], stdout=subprocess.PIPE)
    grep = subprocess.Popen(['grep', 'stuff'], stdin=rpmqa.stdout, stdout=subprocess.PIPE)
    sort = subprocess.Popen(['sort', '-r'], stdin=grep.stdout, stdout=subprocess.PIPE,)

    for line in sort.stdout:
        yield line

撰写回答