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?

Author: smci, 2015-12-15

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.

Co się stało?

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
 151
Author: Bhargav Rao,
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