76

これは、約 21 個のログ ファイルから単純なテキスト処理を行うための Perl および Python スクリプトです。それぞれ約 300 KB から 1 MB (最大) x 5 回繰り返されます (ログが 5 回繰り返されるため、合計 125 ファイル)。

Python コード(コンパイル済みreおよび usingを使用するように変更されたコード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)

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";
    }
}

そして、私の 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

元々、この単純なテキスト処理に、Python を使用すると 10.2 秒、Perl を使用するとわずか 1.9 秒かかりました。

(更新) しかし、Python のコンパイル済みreバージョンの後、Python で 8.2 秒、Perl で 1.5 秒かかるようになりました。それでも、Perl の方がはるかに高速です。

Python の速度をまったく向上させる方法はありますか、それとも単純なテキスト処理では Perl が高速であることは明らかです。

ところで、これは私が単純なテキスト処理のために行った唯一のテストではありませんでした...そして、ソースコードを作成するさまざまな方法で、常に Perl が大きな差で勝っています。そして、Python が単純なm/regex/突き合わせや出力の処理で優れたパフォーマンスを発揮したことは一度もありません。

C、C++、アセンブリ、その他の種類の Python などの使用を提案しないでください。

標準Perlと比較した組み込みモジュールを備えた標準Pythonを使用したソリューションを探しています(モジュールを使用していません)。少年、読みやすさのためにすべてのタスクにPythonを使用したいのですが、速度をあきらめるために、そうは思いません。

ですから、Perl と同等の結果が得られるようにコードを改善する方法を提案してください。

更新: 2012 年 10 月 18 日

他のユーザーが示唆したように、Perl にはその場所があり、Python にはその場所があります。

したがって、この質問については、何百または何千ものテキスト ファイルの各行での単純な正規表現の一致と、結果をファイルに書き込む (または画面に出力する) 場合、Perl は常に、常にこのジョブのパフォーマンスで勝つと安全に結論付けることができます。 . それと同じくらい簡単です。

Perl がパフォーマンスで勝っているという場合、標準的な Perl と Python のみが比較されていることに注意してください...いくつかのあいまいなモジュール (私のような通常のユーザーにはあいまいです) に頼らず、Python から C、C++、アセンブリ ライブラリを呼び出しません。またはパール。単純なテキスト マッチング ジョブの追加の手順とインストールをすべて学習する時間はありません。

したがって、Perl はテキスト処理と正規表現に最適です。

Python には、他の場所で揺るがす場所があります。

2013 年5 月 29 日更新:同様の比較を行う優れた記事はこちらです。Perl は単純なテキスト マッチングで再び勝利します... 詳細については、記事を参照してください。

4

5 に答える 5

14

仮説: Perl は、Python にはない最適化を備えているため、一致しない行でのバックトラックに費やす時間が少なくなります。

交換して得られるもの

^(.*?) INFO.*Such a record already exists

^((?:(?! INFO).)*?) INFO.*Such a record already 

また

^(?>(.*?) INFO).*Such a record already exists
于 2012-10-09T08:02:39.173 に答える
1

Perlの方が速いと思います。ちょっと気になったので、以下を試してみませんか?

#!/usr/bin/python

import re
import glob
import sys
import os

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

for mask in sys.argv[1:]:
    for fname in glob.glob(mask):
        if os.path.isfile(fname):
            f = open(fname)
            for line in f:
                mex = exists_re.search(line)
                if mex:
                    xlogtime = mex.group(1)

                mloc = location_re.search(line)
                if mloc:
                    print fname, xlogtime, mloc.group(1)
            f.close()

「複雑すぎる」への対応として更新します。

もちろん、Perl 版よりも複雑に見えます。Perl は、正規表現を中心に構築されました。このように、正規表現でより高速なインタープリター言語を見つけることはほとんどありません。Perl 構文...

while (<>) {
    ...
}

...また、より一般的な言語で何とかしなければならない多くのことを隠しています。一方、読めない部分を移動すれば、Python コードをより読みやすくするのは非常に簡単です。

#!/usr/bin/python

import re
import glob
import sys
import os

def input_files():
    '''The generator loops through the files defined by masks from cmd.'''
    for mask in sys.argv[1:]:
        for fname in glob.glob(mask):
            if os.path.isfile(fname):
                yield fname


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

for fname in input_files():
    with open(fname) as f:        # Now the f.close() is done automatically
        for line in f:
            mex = exists_re.search(line)
            if mex:
                xlogtime = mex.group(1)

            mloc = location_re.search(line)
            if mloc:
                print fname, xlogtime, mloc.group(1)

ここでは、def input_files()他の場所 (別のモジュールなど) に配置することも、再利用することもできます。while (<>) {...}構文的には同じではありませんが、Perl のものでさえ簡単に模倣することができます。

#!/usr/bin/python

import re
import glob
import sys
import os

def input_lines():
    '''The generator loops through the lines of the files defined by masks from cmd.'''
    for mask in sys.argv[1:]:
        for fname in glob.glob(mask):
            if os.path.isfile(fname):
                with open(fname) as f: # now the f.close() is done automatically
                    for line in f:
                        yield fname, line

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

for fname, line in input_lines():
    mex = exists_re.search(line)
    if mex:
        xlogtime = mex.group(1)

    mloc = location_re.search(line)
    if mloc:
        print fname, xlogtime, mloc.group(1)

後者はfor(原則として) Perl のものと同じくらい簡単に見えるかもしれませんwhile (<>) {...}。このような読みやすさの向上は、Perl ではより困難です。

とにかく、それは Python プログラムを速くしません。Perl はここでも高速になります。Perlファイル/テキスト クランチャーです。しかし、私の意見では、Python はより一般的な目的に適したプログラミング言語です。

于 2012-10-09T08:48:14.230 に答える