TL; DR - WYDANIE 21118
Długa historia
Josh Rosenberg odkrył, że str.translate()
funkcja jest bardzo powolna w porównaniu do bytes.translate
, podniósł problem , stwierdzając, że:
W Pythonie 3 str.translate()
jest to zwykle pesymizacja wydajności, a nie optymalizacja.
Dlaczego był str.translate()
wolny?
Głównym powodem, dla którego str.translate()
było to bardzo powolne, był fakt, że wyszukiwanie odbywało się w słowniku Pythona.
Użycie maketrans
go pogorszyło ten problem. Podobne podejście przy użyciu bytes
buduje tablicę C składającą się z 256 elementów w celu szybkiego wyszukiwania tabeli. Stąd użycie wyższego poziomu Pythona dict
powoduje, że str.translate()
w Pythonie 3.4 jest bardzo powolny.
Co się teraz stało?
Pierwszym podejściem było dodanie małej łatki translate_writer , jednak wzrost szybkości nie był tak przyjemny. Wkrótce testowano kolejną łatkę fast_translate, która dała bardzo dobre wyniki, nawet o 55% przyspieszenia.
Główna zmiana, jak widać z pliku, polega na tym, że przeszukiwanie słownika Pythona zostało zmienione na wyszukiwanie na poziomie C.
Prędkości są teraz prawie takie same jak bytes
unpatched patched
str.translate 4.55125927699919 0.7898181750006188
str.translate from bytes trans 1.8910855210015143 0.779950579000797
Mała uwaga w tym miejscu jest taka, że zwiększenie wydajności jest widoczne tylko w łańcuchach ASCII.
Jak JFSebastian wspomina w komentarzu poniżej, przed 3.5, tłumaczenie działało w ten sam sposób zarówno dla przypadków ASCII, jak i innych niż ASCII. Jednak od 3.5 ASCII sprawa jest znacznie szybsza.
Wcześniej ASCII i inne niż ASCII były prawie takie same, ale teraz widzimy wielką zmianę w wydajności.
Może to być poprawa z 71,6 μs do 2,33 μs, jak widać w tej odpowiedzi .
Poniższy kod demonstruje to
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
Tabela wyników:
Python 3.4 Python 3.5
Ascii 91.2 2.3
Unicode 101 117
dict.fromkeys(ord(c) for c in '@#$')
?