6

数千の大きな正規表現をコンパイルする必要があるプログラムがあり、それらはすべて何度も使用されます。問題は、時間がかかりすぎることです (によるとcProfiler、113 秒) re.compile()。(ところで、実際にこれらすべての正規表現を使用して検索すると、コンパイル後は1.3秒未満です。)

プリコンパイルしないと、re.search(expr, text)暗黙的にコンパイルされるため、実際に検索するときに問題が延期されるだけexprです。実際には、re使用するたびに正規表現のリスト全体を再コンパイルするため、さらに悪いことです。

を使用してみmultiprocessingましたが、実際には速度が低下します。デモ用の小さなテストを次に示します。

## rgxparallel.py ##
import re
import multiprocessing as mp

def serial_compile(strings):
    return [re.compile(s) for s in strings]

def parallel_compile(strings):
    print("Using {} processors.".format(mp.cpu_count()))
    pool = mp.Pool()
    result = pool.map(re.compile, strings)
    pool.close()
    return result

l = map(str, xrange(100000))

そして私のテストスクリプト:

#!/bin/sh
python -m timeit -n 1 -s "import rgxparallel as r" "r.serial_compile(r.l)"
python -m timeit -n 1 -s "import rgxparallel as r" "r.parallel_compile(r.l)"
# Output:
#   1 loops, best of 3: 6.49 sec per loop
#   Using 4 processors.
#   Using 4 processors.
#   Using 4 processors.
#   1 loops, best of 3: 9.81 sec per loop

パラレルバージョンは次のとおりだと思います。

  1. 並行して、正規表現のコンパイルと酸洗、約 2 秒
  2. シリアルで、ピッキングを解除し、したがってそれらすべてを再コンパイルすると、約 6.5 秒

プロセスの開始と停止のオーバーヘッドを合わせると、 4 プロセッサではシリアルmultiprocessingよりも 25% 以上遅くなります。

pool.mapまた、正規表現のリストを4つのサブリストに分割し、個々の式ではなくサブリストを-ingしようとしました。これによりパフォーマンスがわずかに向上しましたが、それでもシリアルよりも最大 25% 遅くなりました。

シリアルよりも速くコンパイルする方法はありますか?

編集: 正規表現コンパイルの実行時間を修正しました。

も使ってみthreadingたのですが、GILのせいでプロセッサが1つしか使えませんでした。(130 秒対 136 秒)よりわずかに優れていましmultiprocessingたが、それでもシリアル (113 秒) よりは遅かったです。

編集 2: 一部の正規表現が重複する可能性があることに気付いたので、それらをキャッシュするための辞書を追加しました。これにより、約 30 秒短縮されました。しかし、私はまだ並列化に興味があります。ターゲット マシンには 8 つのプロセッサがあり、コンパイル時間が ~15 秒に短縮されます。

4

2 に答える 2

-1

私はPythonが大好きですが、解決策はperl (たとえば、この速度比較を参照)またはCなどで行うことだと思います.

メイン プログラムを Python のままにしたい場合はsubprocess、perl スクリプトを呼び出すことができます (subprocessオーバーヘッドを避けるために、できるだけ少ない呼び出しでできるだけ多くの値を渡すようにしてください。

于 2013-08-15T23:26:16.540 に答える