来自stdout的python read()比逐行读取慢得多(slurping?)

Pau*_*ulD 13 python performance subprocess readline

我有一个python SubProcess调用,它运行一个可执行文件并将输出传递给我的子进程stdout.

在stdout数据相对较小(约2k行)的情况下,逐行读取和读取作为块(stdout.read())之间的性能是可比较的... stdout.read()稍快一些.

一旦数据变得更大(比如30k +行),逐行读取的性能就会明显提高.

这是我的比较脚本:

proc=subprocess.Popen(executable,stdout=subprocess.PIPE)
tic=time.clock()
for line in (iter(proc.stdout.readline,b'')):
    tmp.append(line)
print("line by line = %.2f"%(time.clock()-tic))

proc=subprocess.Popen(executable,stdout=subprocess.PIPE)
tic=time.clock()
fullFile=proc.stdout.read()
print("slurped = %.2f"%(time.clock()-tic))
Run Code Online (Sandbox Code Playgroud)

这些是读取~96k行(或50mb磁盘存储器)的结果:

line by line = 5.48
slurped = 153.03
Run Code Online (Sandbox Code Playgroud)

我不清楚为什么性能差异如此极端.我的期望是read()版本应该比逐行存储结果更快.当然,在实际情况下我期望更快的逐行结果,其中在读取期间可以进行显着的每行处理.

任何人都可以让我深入了解read()性能成本吗?

Dan*_*der 4

这不仅仅是Python,在没有缓冲的情况下按字符读取总是比读入行或大块慢。

考虑这两个简单的 C 程序:

[readchars.c]

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

int main(void) {
        FILE* fh = fopen("largefile.txt", "r");
        if (fh == NULL) {
                perror("Failed to open file largefile.txt");
                exit(1);
        }

        int c;
        c = fgetc(fh);
        while (c != EOF) {
                c = fgetc(fh);
        }

        return 0;
}
Run Code Online (Sandbox Code Playgroud)

[readlines.c]

#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

int main(void) {
        FILE* fh = fopen("largefile.txt", "r");
        if (fh == NULL) {
                perror("Failed to open file largefile.txt");
                exit(1);
        }

        char* s = (char*) malloc(120);
        s = fgets(s, 120, fh);
        while ((s != NULL) && !feof(fh)) {
                s = fgets(s, 120, fh);
        }

        free(s);

        return 0;
}
Run Code Online (Sandbox Code Playgroud)

他们的结果(YMMW,largefile.txt 约为 200MB 文本文件):

$ gcc readchars.c -o readchars
$ time ./readchars            
./readchars  1.32s user 0.03s system 99% cpu 1.350 total
$ gcc readlines.c -o readlines
$ time ./readlines            
./readlines  0.27s user 0.03s system 99% cpu 0.300 total
Run Code Online (Sandbox Code Playgroud)