TL; DR - ВЫПУСК 21118
Длинная история
Джош Розенберг обнаружил, что эта str.translate()
функция очень медленная по сравнению с bytes.translate
, он поднял вопрос , заявив, что:
В Python 3 str.translate()
обычно идет пессимизация производительности, а не оптимизация.
Почему было str.translate()
медленно?
Основная причина str.translate()
очень медленной работы заключалась в том, что поиск выполнялся в словаре Python.
Использование maketrans
усугубило эту проблему. Аналогичный подход с использованием bytes
создает массив C из 256 элементов для быстрого поиска в таблице. Следовательно, использование 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, translate работал одинаково как для ASCII, так и для случаев, отличных от ASCII. Однако с 3.5 ASCII дело намного быстрее.
Раньше ASCII и не-ascii были почти одинаковыми, но теперь мы можем видеть большие изменения в производительности.
Это может быть улучшение с 71,6 мкс до 2,33 мкс, как видно из этого ответа .
Следующий код демонстрирует это
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 '@#$')
:?