繁体   English   中英

提高Python代码性能

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM