Dlaczego jest str.tłumaczyć znacznie szybciej w Pythonie 3.5 w porównaniu do Pythona 3.4?
Próbowałem usunąć niechciane znaki z danego ciągu używając text.translate()
w Pythonie 3.4.
Minimalny kod to:
import sys
s = 'abcde12345@#@$#%$'
mapper = dict.fromkeys(i for i in range(sys.maxunicode) if chr(i) in '@#$')
print(s.translate(mapper))
Działa zgodnie z oczekiwaniami. Jednak ten sam program po wykonaniu w Pythonie 3.4 i Pythonie 3.5 daje dużą różnicę.
Kod do obliczania czasu to
python3 -m timeit -s "import sys;s = 'abcde12345@#@$#%$'*1000 ; mapper = dict.fromkeys(i for i in range(sys.maxunicode) if chr(i) in '@#$'); " "s.translate(mapper)"
Program Python 3.4 zajmuje 1.3 ms natomiast ten sam program w Pythonie 3.5 zajmuje tylko 26.4 µs.
Co poprawiło się w Pythonie 3.5, co czyni go szybszym w porównaniu do Pythona 3.4?
1 answers
TL; DR - PROBLEM 21118
Długa historia
Josh Rosenberg dowiedział się, że funkcja str.translate()
jest bardzo powolna w porównaniu do bytes.translate
, podniósł problem , stwierdzając, że:
W Pythonie 3,
str.translate()
jest zwykle pesymizacją wydajności, a nie optymalizacją.
Dlaczego str.translate()
był powolny?
Głównym powodem str.translate()
aby być bardzo powolnym było to, że lookup kiedyś w Pythonie słownik.
Użycie maketrans
pogorszyło ten problem. Podobne podejście przy użyciu bytes
buduje tablicę C zawierającą 256 elementów do szybkiego przeszukiwania tabeli. Dlatego użycie Pythona wyższego poziomu dict
sprawia, że str.translate()
w Pythonie 3.4 jest bardzo powolne.
Pierwszym podejściem było dodanie małej łatki translate_writer , jednak wzrost prędkości nie był aż tak przyjemny. Wkrótce kolejny patch fast_translate został przetestowany i dał bardzo ładne wyniki do 55% speedup.
Główną zmianą, jaką widać z pliku, jest to, że wyszukiwanie słownika Pythona jest zmieniane 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 jest tutaj, że poprawa wydajności jest widoczna tylko w strunach ASCII.
Jak wspomina J. F. Sebastian w komentarz poniżej, przed 3.5, translate działał w ten sam sposób zarówno dla ASCII, jak i nie-ASCII sprawy. Jednak od 3.5 ASCII sprawa jest znacznie szybsza.
Wcześniej ASCII vs non-ascii były prawie takie same, jednak teraz widzimy wielką zmianę w wydajności.
Może to być poprawa z 71,6 µs do 2,33 µs, jak widać w tej odpowiedź .
Poniższy kod pokazuje 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
Zestawienie wyników:
Python 3.4 Python 3.5
Ascii 91.2 2.3
Unicode 101 117
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:30