数千の大きな正規表現をコンパイルする必要があるプログラムがあり、それらはすべて何度も使用されます。問題は、時間がかかりすぎることです (によると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
パラレルバージョンは次のとおりだと思います。
- 並行して、正規表現のコンパイルと酸洗、約 2 秒
- シリアルで、ピッキングを解除し、したがってそれらすべてを再コンパイルすると、約 6.5 秒
プロセスの開始と停止のオーバーヘッドを合わせると、 4 プロセッサではシリアルmultiprocessing
よりも 25% 以上遅くなります。
pool.map
また、正規表現のリストを4つのサブリストに分割し、個々の式ではなくサブリストを-ingしようとしました。これによりパフォーマンスがわずかに向上しましたが、それでもシリアルよりも最大 25% 遅くなりました。
シリアルよりも速くコンパイルする方法はありますか?
編集: 正規表現コンパイルの実行時間を修正しました。
も使ってみthreading
たのですが、GILのせいでプロセッサが1つしか使えませんでした。(130 秒対 136 秒)よりわずかに優れていましmultiprocessing
たが、それでもシリアル (113 秒) よりは遅かったです。
編集 2: 一部の正規表現が重複する可能性があることに気付いたので、それらをキャッシュするための辞書を追加しました。これにより、約 30 秒短縮されました。しかし、私はまだ並列化に興味があります。ターゲット マシンには 8 つのプロセッサがあり、コンパイル時間が ~15 秒に短縮されます。