Я пытался удалить ненужные символы из заданной строки, используя text.translate()
Python 3.4.
Минимальный код:
import sys
s = 'abcde12345@#@$#%$'
mapper = dict.fromkeys(i for i in range(sys.maxunicode) if chr(i) in '@#$')
print(s.translate(mapper))
Работает как положено. Однако одна и та же программа при выполнении в Python 3.4 и Python 3.5 дает большую разницу.
Код для расчета таймингов:
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)"
Программа Python 3.4 занимает 1,3 мс, тогда как та же программа в Python 3.5 занимает всего 26,4 мкс .
Что улучшено в Python 3.5, что делает его быстрее по сравнению с Python 3.4?
python
string
python-3.x
python-internals
python-3.5
Бхаргав Рао
источник
источник
dict.fromkeys(ord(c) for c in '@#$')
:?Ответы:
TL; DR - ВЫПУСК 21118
Длинная история
Джош Розенберг обнаружил, что эта
str.translate()
функция очень медленная по сравнению сbytes.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
Небольшое замечание: повышение производительности заметно только в строках ASCII.
Как упоминает JFSebastian в комментарии ниже, до 3.5, translate работал одинаково как для ASCII, так и для случаев, отличных от ASCII. Однако с 3.5 ASCII дело намного быстрее.
Раньше ASCII и не-ascii были почти одинаковыми, но теперь мы можем видеть большие изменения в производительности.
Это может быть улучшение с 71,6 мкс до 2,33 мкс, как видно из этого ответа .
Следующий код демонстрирует это
Табулирование результатов:
источник
55
%: как показывает ваш ответ, скорость может быть1000
s% .python3.5 -m timeit -s "text = 'mJssissippi'*100; d=dict(J='i')" "text.translate(d)"
(ascii) vs.python3.5 -m timeit -s "text = 'm\U0001F602ssissippi'*100; d={'\U0001F602': 'i'}" "text.translate(d)"
(non-ascii). Последний намного (в 10 раз) медленнее..translate()
т.е. регистр ascii намного быстрее только в Python 3.5 (вам не нужнаbytes.translate()
производительность там).