TL; DR - AUSGABE 21118
Die lange Geschichte
Josh Rosenberg fand heraus, dass die str.translate()
Funktion im Vergleich zu sehr langsam bytes.translate
ist. Er warf ein Problem auf und erklärte:
In Python 3 str.translate()
handelt es sich normalerweise um eine Leistungspessimierung, nicht um eine Optimierung.
Warum war str.translate()
langsam?
Der Hauptgrund dafür str.translate()
, sehr langsam zu sein, war, dass sich die Suche früher in einem Python-Wörterbuch befand.
Die Verwendung von maketrans
machte dieses Problem noch schlimmer. Bei einem ähnlichen Ansatz wird bytes
ein C-Array mit 256 Elementen erstellt, um eine schnelle Tabellensuche zu ermöglichen. Daher macht die Verwendung von höherstufigem Python dict
das str.translate()
in Python 3.4 sehr langsam.
Was ist gerade passiert?
Der erste Ansatz bestand darin, einen kleinen Patch, translate_writer , hinzuzufügen. Die Geschwindigkeitssteigerung war jedoch nicht so erfreulich. Bald wurde ein weiterer Patch fast_translate getestet, der sehr gute Ergebnisse mit einer Beschleunigung von bis zu 55% lieferte.
Die wichtigste Änderung, die aus der Datei hervorgeht, besteht darin, dass die Python-Wörterbuchsuche in eine C-Level-Suche geändert wird.
Die Geschwindigkeiten sind jetzt fast die gleichen wie bytes
unpatched patched
str.translate 4.55125927699919 0.7898181750006188
str.translate from bytes trans 1.8910855210015143 0.779950579000797
Eine kleine Anmerkung hier ist, dass die Leistungsverbesserung nur in ASCII-Zeichenfolgen prominent ist.
Wie JFSebastian in einem Kommentar unten erwähnt, funktioniert Übersetzen vor 3.5 in ASCII- und Nicht-ASCII-Fällen auf dieselbe Weise. Ab 3.5 ASCII ist der Fall jedoch viel schneller.
Früher waren ASCII und Nicht-ASCII fast gleich, jetzt können wir jedoch eine große Veränderung in der Leistung feststellen.
Dies kann eine Verbesserung von 71,6 μs auf 2,33 μs sein, wie in dieser Antwort gezeigt .
Der folgende Code demonstriert dies
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
Tabelle der Ergebnisse:
Python 3.4 Python 3.5
Ascii 91.2 2.3
Unicode 101 117
dict.fromkeys(ord(c) for c in '@#$')
?