[英]Improve Python code performance
如何提高这个简单的python代码的性能? 不是re.search
是寻找匹配线的最佳方法,因为它比Perl慢近6倍,或者我做错了什么?
#!/usr/bin/env python
import re
import time
import sys
i=0
j=0
time1=time.time()
base_register =r'DramBaseAddress\d+'
for line in open('rndcfg.cfg'):
i+=1
if(re.search(base_register, line)):
j+=1
time2=time.time()
print (i,j)
print (time2-time1)
print (sys.version)
此代码大约需要0.96秒才能完成(平均10次运行)
输出:
168197 2688
0.8597519397735596
3.3.2 (default, Sep 24 2013, 15:14:17)
[GCC 4.1.1]
而以下Perl代码在0.15秒内完成。
#!/usr/bin/env perl
use strict;
use warnings;
use Time::HiRes qw(time);
my $i=0;my $j=0;
my $time1=time;
open(my $fp, 'rndcfg.cfg');
while(<$fp>)
{
$i++;
if(/DramBaseAddress\d+/)
{
$j++;
}
}
close($fp);
my $time2=time;
printf("%d,%d\n",$i,$j);
printf("%f\n",$time2-$time1);
printf("%s\n",$]);
输出:
168197,2688
0.135579
5.012001
编辑:更正了正则表达式 - 这使性能略有恶化
实际上,正则表达式的效率低于Python中的字符串方法。 来自https://docs.python.org/2/howto/regex.html#use-string-methods :
字符串有几种方法可以使用固定字符串执行操作,它们通常要快得多,因为实现是一个针对此目的而优化的单个小C循环,而不是大型,更通用的正则表达式引擎。
用str.find
替换re.search
将为您提供更好的运行时。 否则,使用其他人建议的in
运算符也会进行优化。
至于Python和Perl版本之间的速度差异,我只是简单介绍每种语言的内在质量: 文本处理 - python vs perl性能
在这种情况下,您使用的是固定字符串,而不是正则表达式。
对于常规字符串,有更快的方法:
>>> timeit.timeit('re.search(regexp, "banana")', setup = "import re; regexp=r'nan'")
1.2156920433044434
>>> timeit.timeit('"banana".index("nan")')
0.23752403259277344
>>> timeit.timeit('"banana".find("nan")')
0.2411658763885498
现在,这种文本处理是Perl(又名实用提取和报告语言)(又名病态折衷垃圾列表)的最佳点,并且多年来已经进行了广泛的优化。 所有集体关注的焦点都在增加。
尽管有缓存,调用re.compile
的开销很大。 使用
is_wanted_line = re.compile(r"DramBaseAddress\d+").search
for i, line in enumerate(open('rndcfg.cfg')):
if is_wanted_line(line):
j += 1
代替。
此外,你可以做到
key = "DramBaseAddress"
is_wanted_line = re.compile(r"DramBaseAddress\d+").search
for i, line in enumerate(open('rndcfg.cfg')):
if key in line and is_wanted_line(line):
j += 1
进一步减少开销。
你也可以考虑做自己的缓冲:
key = b"DramBaseAddress"
is_wanted_line = re.compile(rb"DramBaseAddress\d+").search
with open("rndcfg.cfg", "rb") as file:
rest = b""
for chunk in iter(lambda: file.read(32768), b""):
i += chunk.count(b"\n")
chunk, _, rest = (rest + chunk).rpartition(b"\n")
if key in rest and is_wanted_line(chunk):
j += 1
if key in rest and is_wanted_line(rest):
j += 1
这消除了行分割和编码开销。 (这不完全相同,因为它没有考虑每个块的多个实例。这样的行为添加相对简单,但在您的情况下可能不是严格需要的。)
这有点重量级,但是如果你移除i += chunk.count(b"\\n")
就像Perl一样快 - 8x!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.