TL; DR-問題21118
長い物語
Josh Rosenberg str.translate()
は、関数がに比べて非常に遅いことを発見しbytes.translate
、問題を提起して、次のように述べています。
Python 3では、str.translate()
通常、最適化ではなくパフォーマンスの悲観化です。
なぜstr.translate()
遅いのですか?
str.translate()
非常に遅くなる主な理由は、以前はPython辞書で検索を行っていたためです。
の使用によりmaketrans
、この問題は悪化しました。を使用bytes
した同様のアプローチでは、256項目のC配列を作成して、テーブルを高速に検索します。したがって、より高いレベルのPython dict
を使用するとstr.translate()
、Python 3.4のが非常に遅くなります。
今何が起きたの?
最初のアプローチは小さなパッチtranslate_writerを追加することでしたが、速度の向上はそれほど楽しいものではありませんでした。まもなく別のパッチfast_translateがテストされ、最大55%のスピードアップという非常に優れた結果が得られました。
ファイルからわかる主な変更は、Python辞書のルックアップがCレベルのルックアップに変更されていることです。
速度は今とほぼ同じです bytes
unpatched patched
str.translate 4.55125927699919 0.7898181750006188
str.translate from bytes trans 1.8910855210015143 0.779950579000797
ここでの注意点は、パフォーマンスの向上はASCII文字列でのみ顕著であることです。
JFSebastianが以下のコメントで言及しているように、3.5より前の翻訳は、ASCIIと非ASCIIの両方のケースで同じように機能するように使用されていました。ただし、3.5以降のASCIIケースははるかに高速です。
以前のASCIIと非ASCIIはほぼ同じでしたが、パフォーマンスに大きな変化が見られます。
この回答に示されているように、71.6μsから2.33μsに改善される可能性があります。
次のコードはこれを示しています
python3.5 -m timeit -s "text = 'mJssissippi'*100; d=dict(J='i')" "text.translate(d)"
100000 loops, best of 3: 2.3 usec per loop
python3.5 -m timeit -s "text = 'm\U0001F602ssissippi'*100; d={'\U0001F602': 'i'}" "text.translate(d)"
10000 loops, best of 3: 117 usec per loop
python3 -m timeit -s "text = 'm\U0001F602ssissippi'*100; d={'\U0001F602': 'i'}" "text.translate(d)"
10000 loops, best of 3: 91.2 usec per loop
python3 -m timeit -s "text = 'mJssissippi'*100; d=dict(J='i')" "text.translate(d)"
10000 loops, best of 3: 101 usec per loop
結果の表:
Python 3.4 Python 3.5
Ascii 91.2 2.3
Unicode 101 117
dict.fromkeys(ord(c) for c in '@#$')
でしょう。