文本处理 - Python与Perl性能

ihi*_*wer 67 python regex perl performance text-processing

这是我的Perl和Python脚本,用于从大约21个日志文件进行一些简单的文本处理,每个大约300 KB到1 MB(最大)x重复5次(总共125个文件,由于日志重复5次).

Python代码(修改后使用编译re和使用的代码re.I)

#!/usr/bin/python

import re
import fileinput

exists_re = re.compile(r'^(.*?) INFO.*Such a record already exists', re.I)
location_re = re.compile(r'^AwbLocation (.*?) insert into', re.I)

for line in fileinput.input():
    fn = fileinput.filename()
    currline = line.rstrip()

    mprev = exists_re.search(currline)

    if(mprev):
        xlogtime = mprev.group(1)

    mcurr = location_re.search(currline)

    if(mcurr):
        print fn, xlogtime, mcurr.group(1)
Run Code Online (Sandbox Code Playgroud)

Perl代码

#!/usr/bin/perl

while (<>) {
    chomp;

    if (m/^(.*?) INFO.*Such a record already exists/i) {
        $xlogtime = $1;
    }

    if (m/^AwbLocation (.*?) insert into/i) {
        print "$ARGV $xlogtime $1\n";
    }
}
Run Code Online (Sandbox Code Playgroud)

并且,在我的PC上,两个代码生成完全相同的10,790行结果文件.而且,这是在Cygwin的Perl和Python实现上完成的时间.

User@UserHP /cygdrive/d/tmp/Clipboard
# time /tmp/scripts/python/afs/process_file.py *log* *log* *log* *log* *log* >
summarypy.log

real    0m8.185s
user    0m8.018s
sys     0m0.092s

User@UserHP /cygdrive/d/tmp/Clipboard
# time /tmp/scripts/python/afs/process_file.pl *log* *log* *log* *log* *log* >
summarypl.log

real    0m1.481s
user    0m1.294s
sys     0m0.124s
Run Code Online (Sandbox Code Playgroud)

最初,使用Python需要10.2秒,使用Perl仅需1.9秒就可以进行简单的文本处理.

(更新)但是,在rePython 的编译版本之后,它在Python中需要8.2秒,在Perl中需要1.5秒.Perl的速度要快得多.

有没有办法提高Python的速度或者很明显Perl将是快速的简单文本处理.

顺便说一下,这不是我为简单文本处理所做的唯一测试......而且,我制作源代码的每种不同方式,总是Perl赢得大幅度.并且,Python没有一次表现出更好的简单m/regex/匹配和打印内容.

请不要建议使用C,C++,汇编,其他版本的Python等.

我正在寻找使用标准Python的解决方案,其内置模块与标准Perl(甚至不使用模块)进行比较.男孩,由于其可读性,我希望将Python用于我的所有任务,但是为了放弃速度,我不这么认为.

因此,请建议如何改进代码以获得与Perl相当的结果.

更新时间:2012-10-18

正如其他用户所建议的那样,Perl有它的位置,Python也有它的地位.

因此,对于这个问题,人们可以有把握地得出结论,对于数百或数千个文本文件的每行上的简单正则表达式匹配并将结果写入文件(或打印到屏幕),Perl将始终为此作业赢得性能.就这么简单.

请注意,当我说Perl在性能上获胜时...只比较标准的Perl和Python ...不要求助于一些模糊的模块(对于像我这样的普通用户而言模糊不清)而且也没有从Python调用C,C++,汇编库或者Perl.我们没有时间为简单的文本匹配工作学习所有这些额外的步骤和安装.

因此,Perl晃动文本处理和正则表达式.

Python有其他地方可以摇滚的地方.

更新2013-05-29:这里做了类似比较的优秀文章.Perl再次赢得了简单的文本匹配...有关更多详细信息,请阅读文章.

Jos*_*ght 18

这正是Perl设计的那种东西,所以它不会让我感到惊讶的是它更快.

Python代码中的一个简单优化就是预编译这些正则表达式,因此每次都不会重新编译它们.

exists_re = re.compile(r'^(.*?) INFO.*Such a record already exists')
location_re = re.compile(r'^AwbLocation (.*?) insert into')
Run Code Online (Sandbox Code Playgroud)

然后在你的循环中:

mprev = exists_re.search(currline)
Run Code Online (Sandbox Code Playgroud)

mcurr = location_re.search(currline)
Run Code Online (Sandbox Code Playgroud)

这本身不会神奇地使你的Python脚本与你的Perl脚本保持一致,但是在没有首先编译的情况下重复调用re是Python中的坏习惯.

  • @nneonneo我已经听过很多次了,我已经看到了`re`源代码中用来进行缓存的行.但不知怎的,我从来没有见过将这两者放在同一数量级的基准测试,但有几个基准测试(包括我之前做过的快速而肮脏的测试),它使预编译选项的速度提高了好几倍. (5认同)
  • `re`缓存最近使用的正则表达式,所以这可能不是一个大问题. (3认同)
  • 有趣.好吧,预编译正则表达式绝对是好习惯,但我并没有真正关注性能差距.小心分享数字? (3认同)

ike*_*ami 14

假设:由于Python不具备的优化,Perl在不匹配的行中花费较少的时间回溯.

替换你得到什么?

^(.*?) INFO.*Such a record already exists
Run Code Online (Sandbox Code Playgroud)

^((?:(?! INFO).)*?) INFO.*Such a record already 
Run Code Online (Sandbox Code Playgroud)

要么

^(?>(.*?) INFO).*Such a record already exists
Run Code Online (Sandbox Code Playgroud)


jrd*_*rd1 2

一般来说,所有人为的基准都是邪恶的。然而,在其他条件相同的情况下(算法方法),您可以在相对基础上进行改进。然而,应该指出的是,我不使用 Perl,所以我不能支持它。话虽如此,对于 Python,您可以尝试使用PyrexCython来提高性能。或者,如果您喜欢冒险,您可以尝试通过ShedSkin将 Python 代码转换为 C++ (适用于大多数核心语言,以及一些(但不是全部)核心模块)。

不过,您可以遵循此处发布的一些提示:

http://wiki.python.org/moin/PythonSpeed/PerformanceTips

  • -1。这有什么“邪”呢?这是一个简单的练习,说明了两种语言之间显着的性能差异。如果不进行这样的测试,您究竟应该如何比较两个工具的性能?用两种语言编写整个程序,这样它就不是“人造的”?当然,基准测试存在陷阱,但您已将其概括为一个非常愚蠢的规则。 (11认同)