【发布时间】:2016-08-02 06:15:00
【问题描述】:
我有一个包含一百万行的压缩数据文件:
$ zcat million_lines.txt.gz | head
1
2
3
4
5
6
7
8
9
10
...
我处理这个文件的 Perl 脚本如下:
# read_million.pl
use strict;
my $file = "million_lines.txt.gz" ;
open MILLION, "gzip -cdfq $file |";
while ( <MILLION> ) {
chomp $_;
if ($_ eq "1000000" ) {
print "This is the millionth line: Perl\n";
last;
}
}
在 Python 中:
# read_million.py
import gzip
filename = 'million_lines.txt.gz'
fh = gzip.open(filename)
for line in fh:
line = line.strip()
if line == '1000000':
print "This is the millionth line: Python"
break
无论出于何种原因,Python 脚本花费的时间几乎要长约 8 倍:
$ time perl read_million.pl ; time python read_million.py
This is the millionth line: Perl
real 0m0.329s
user 0m0.165s
sys 0m0.019s
This is the millionth line: Python
real 0m2.663s
user 0m2.154s
sys 0m0.074s
我尝试分析这两个脚本,但实际上没有多少代码可以分析。 Python 脚本大部分时间都花在for line in fh 上; Perl 脚本大部分时间都花在if($_ eq "1000000")。
现在,我知道 Perl 和 Python 有一些预期的差异。例如,在 Perl 中,我使用 UNIX gzip 命令的子进程打开文件句柄;在 Python 中,我使用 gzip 库。
我可以做些什么来加速这个脚本的 Python 实现(即使我从来没有达到 Perl 的性能)?也许 Python 中的 gzip 模块很慢(或者我使用它的方式不好);有没有更好的解决方案?
编辑 #1
这是 read_million.py 逐行分析的样子。
Line # Hits Time Per Hit % Time Line Contents
==============================================================
2 @profile
3 def main():
4
5 1 1 1.0 0.0 filename = 'million_lines.txt.gz'
6 1 472 472.0 0.0 fh = gzip.open(filename)
7 1000000 5507042 5.5 84.3 for line in fh:
8 1000000 582653 0.6 8.9 line = line.strip()
9 1000000 443565 0.4 6.8 if line == '1000000':
10 1 25 25.0 0.0 print "This is the millionth line: Python"
11 1 0 0.0 0.0 break
编辑 #2:
我现在也按照@Kirk Strauser 和其他人尝试了subprocess python 模块。它更快:
Python“子进程”解决方案:
# read_million_subproc.py
import subprocess
filename = 'million_lines.txt.gz'
gzip = subprocess.Popen(['gzip', '-cdfq', filename], stdout=subprocess.PIPE)
for line in gzip.stdout:
line = line.strip()
if line == '1000000':
print "This is the millionth line: Python"
break
gzip.wait()
这是我迄今为止尝试过的所有事情的比较表:
method average_running_time (s)
--------------------------------------------------
read_million.py 2.708
read_million_subproc.py 0.850
read_million.pl 0.393
【问题讨论】:
-
您是否尝试过在 Python 中使用 Perl gzip 库或外部 gzip 管道?
-
IIRC,Python的
gzip模块是用Python写的,所以性能很差。 OrangeDog 建议在外部运行gzip并将解压缩的输出传输到 Python 可能会加快速度。 -
哇。对我来说,“炮轰”到 zcat 是理想的,这非常违反直觉......
-
@asf107:问题在于您在第一种情况下并没有真正使用 Perl。也就是说,Perl 是为文本处理设计的。如果任务只是消耗文本并处理它,那么 Perl 很可能会获胜。哎呀,根据我的经验,Perl 通常会更快一些(尽管当您使用其被破解的 OO 功能时它会失去优势),因为字符串可变(当您
strip或切片时,Python 正在复制,Perl 正在发生变异chomp),并改进了名称查找(Perl 在编译时链接非 OO 名称;Python 在运行时一遍又一遍地查找它们)。
标签: python performance perl