#python #python-3.x #performance
#python #python-3.x #Производительность
Вопрос:
Пожалуйста, рассмотрите следующий код. Цель здесь — создать типичный дамп двоичных данных ascii, заменив непечатаемые символы на '.'
.
Оба сегмента кода выводят один и тот же результат. Второй кажется более «питоническим», но (по моим измерениям) в 2-3 раза медленнее первого, предположительно потому, что он создает больше временных объектов.
Поскольку я собираюсь делать это много миллионов раз, производительность имеет значение. Есть ли более быстрый Pythonic способ сделать это?
ba = bytearray.fromhex("01610262") # non-printable binary data, 'a', binary, 'b'
for i in range(len(ba)):
if not chr(ba[i]).isprintable():
ba[i] = ord('.')
text = ba.decode("ascii")
print(text) # prints ".a.b"
ba = bytearray.fromhex("01610262")
text = bytes(map(lambda b: ord('.') if not chr(b).isprintable() else b, ba)).decode("ascii")
print(text) # prints ".a.b"
Версия с измерением производительности:
ITERATIONS=1000000
start = time.time()
for z in range(ITERATIONS):
ba = bytearray.fromhex("01610262")
for i in range(0, len(ba)):
if not chr(ba[i]).isprintable():
ba[i] = ord('.')
text = ba.decode("ascii")
#print(text)
end = time.time()
print("first elapsed time:", (end-start))
start = time.time()
for z in range(ITERATIONS):
ba = bytearray.fromhex("01610262")
text = bytes(map(lambda b: ord('.') if not chr(b).isprintable() else b, ba)).decode("ascii")
#print(text)
end = time.time()
print("second elapsed time:", (end-start))
Выводит:
first elapsed time: 2.4349358081817627
second elapsed time: 5.805044889450073
Обновить:
Обнаружил, что запуск теста синхронизации из командной строки вместо моей IDE (к которой был подключен отладчик) как увеличил производительность, так и радикально уменьшил разницу в производительности.
Принятый ответ (с использованием таблицы перевода) намного быстрее при запуске из командной строки.
Решение Марата «.join() в комментариях находится между первым и вторым вариантами, приведенными выше, при запуске из командной строки (но намного хуже в моем отладчике [с использованием расширений Visual Studio Code Python].)
Комментарии:
1.
timeit
показывает гораздо менее значительную разницу между этими подходами, 735n против 864n. Разница может быть связана с тем, как распределяются переменные, а не с эффективностью метода2.
''.join(chr(b) if b < 127 else '.' for b in ba)
только немного быстрее (645n), но определенно более удобочитаем3. не могли бы вы создать лямбда-функцию вне
map
функции. Это улучшит скорость4. @Marat — спасибо за предложение присоединиться. В моих тестах он упал между первым и вторым по времени — при запуске из команды. При запуске в моей IDE (которая подключает отладчик), это на порядок медленнее.
Ответ №1:
Если вас беспокоит настройка таблицы перевода, то я получил гораздо лучшие результаты, используя этот метод в вашем примере.
btrans = bytes.maketrans(b'x01x02',b'..')
for z in range(ITERATIONS):
ba = bytearray.fromhex("01610262")
text = ba.translate(btrans).decode('ascii')
#print(text)
end = time.time()
print("third elapsed time:", (end-start))
first elapsed time: 1.4424219131469727
second elapsed time: 1.1425127983093262
third elapsed time: 0.3709402084350586
Комментарии:
1. Настройка таблицы перевода стоила увеличения производительности. Спасибо! @jonathan