Python: «снять маску» с длинной строки данных, обработанной XOR ⇐ Python
-
Anonymous
Python: «снять маску» с длинной строки данных, обработанной XOR
В рамках спецификации WebSocket все кадры, отправленные клиентом, должны иметь часть полезной нагрузки кадров, замаскированную с использованием 4-байтовой маски. На C++ это было бы очень просто:
for (size_t i = 0; i < length; i++) { данные ^= маска[i % 4]; } К сожалению, строки Python неизменяемы, и я бы предпочел избегать подобных действий из-за постоянного копирования и повторного создания строкового буфера:
frame = '' для я в диапазоне (0, длина-1): кадр += chr(ord(oldFrame) ^ ord(маска[i % 4])) Итак, после некоторых исследований я нашел вот это:
m = itertools.cycle(маска) Frame = ''.join(chr(ord(x) ^ ord(y)) для (x,y) в itertools.izip(oldFrame, m)) В CPython это вдвое сократило время, необходимое для демаскирования. В PyPy для замаскированной строки размером 16 МБ это легко увеличивается до 1,5 ГБ ОЗУ, после чего начинается замена, и мне приходится ее убить. CPython использует «всего» 150 МБ ОЗУ для этой строки размером 16 МБ (и это занимает 20 секунд), но это все равно плохо. Для сравнения, мой тест C++ сделал это за 0,05 секунды без каких-либо затрат памяти.
Конечно, это крайности, которых на самом деле не произойдет, когда программное обеспечение перейдет в производственный режим (все входящие данные ограничены 10 КБ), но мне бы очень хотелось получить хороший результат в этом тесте.
Есть идеи? Единственные требования: быстрая работа как на CPython, так и на PyPy, а также низкое использование памяти. Исходную строку сохранять не обязательно.
Небольшой тестовый код для тех, кто хочет поэкспериментировать:
импортировать ОС, время кадр = os.urandom(16
В рамках спецификации WebSocket все кадры, отправленные клиентом, должны иметь часть полезной нагрузки кадров, замаскированную с использованием 4-байтовой маски. На C++ это было бы очень просто:
for (size_t i = 0; i < length; i++) { данные ^= маска[i % 4]; } К сожалению, строки Python неизменяемы, и я бы предпочел избегать подобных действий из-за постоянного копирования и повторного создания строкового буфера:
frame = '' для я в диапазоне (0, длина-1): кадр += chr(ord(oldFrame) ^ ord(маска[i % 4])) Итак, после некоторых исследований я нашел вот это:
m = itertools.cycle(маска) Frame = ''.join(chr(ord(x) ^ ord(y)) для (x,y) в itertools.izip(oldFrame, m)) В CPython это вдвое сократило время, необходимое для демаскирования. В PyPy для замаскированной строки размером 16 МБ это легко увеличивается до 1,5 ГБ ОЗУ, после чего начинается замена, и мне приходится ее убить. CPython использует «всего» 150 МБ ОЗУ для этой строки размером 16 МБ (и это занимает 20 секунд), но это все равно плохо. Для сравнения, мой тест C++ сделал это за 0,05 секунды без каких-либо затрат памяти.
Конечно, это крайности, которых на самом деле не произойдет, когда программное обеспечение перейдет в производственный режим (все входящие данные ограничены 10 КБ), но мне бы очень хотелось получить хороший результат в этом тесте.
Есть идеи? Единственные требования: быстрая работа как на CPython, так и на PyPy, а также низкое использование памяти. Исходную строку сохранять не обязательно.
Небольшой тестовый код для тех, кто хочет поэкспериментировать:
импортировать ОС, время кадр = os.urandom(16
Мобильная версия