#javascript #node.js
#javascript #node.js
Вопрос:
Как обсуждается в этом потоке GitHub, есть причина Map
.has
, по которой метод ‘s не работает с буферами, поскольку два идентичных буфера фактически являются двумя разными, разными объектами.
Поэтому, когда я попытался сохранить преобразования строк буфера в карту, чтобы кэшировать результаты, чтобы проверить потенциальную возможность оптимизации путем кэширования результатов Buffer.toString('utf8')
на карте, я был разочарован. Конечно, я могу преобразовать буфер в какую-либо другую форму, чтобы привязать его к карте, но тогда мне также придется преобразовывать его каждый раз, когда я тестирую кеш, что в некотором роде противоречит цели.
const readStr = (buffer) => {
if (strMap.has(buffer)) {
return strMap.get(buffer)
} else {
result = buffer.toString("utf8");
strMap.set(buffer, result)
return result
}
}
Итак, я решил, что должен просто спросить. Существует ли жизнеспособный способ кэширования .toString()
результатов буфера? Возможна ли такая оптимизация в JavaScript?
Редактировать: количество возможных уникальных строк в моих данных известно и мало (< 10000), и все строки в моем варианте использования имеют длину 5.
Комментарии:
1. Я не думаю, что это стоит усилий. Движки JavaScript оптимизированы для
string
эффективной обработки значений, даже недолговечных строк. Какое профилирование или сравнительный анализ вы выполнили, что предполагает, что вы должны запоминать это в любом случае? (Источник: я работал над Chakra в Microsoft) (не говоря уже о затратах памяти на запоминание каждой возможной строки в любом из ваших буферов (иначе интернирование строк) — ой!)2. Что, если вместо использования всего Buffer.toString в качестве кэша (по сути) вы используете некоторый хэш в качестве ключа?
3. @raina77ow Вычислительные затраты на вычисление хэша буфера будут на тот же порядок, что и при вызове
toString
, и потенциально на самом деле хуже , учитывая, чтоtoString
это обычно реализуется в машинном коде внутри движка, в то время как хеширование буфера должно выполняться с использованием других JS.4. @Dai согласился. Думал о немного других случаях, связанных с внешними ресурсами вместо буферов.
5. @Dai Я покажу вам, почему я, по крайней мере, пытаюсь это сделать. См. Строки 119 — 126. gist.github.com/jt0dd/b9c57298dab7af97bc3fd3d51e06e3f0 . В сценарии, для которого я хотел бы достичь абсолютной максимальной скорости чтения
readBuffer
, преобразование строк является самым медленным. Я просто заинтересован в тестировании всех возможных оптимизаций
Ответ №1:
Я понял это. Это решение для кэширования дает улучшение на 25%:
const readStr = (buffer) => {
key = "" buffer[0] buffer[1] buffer[2] buffer[3] buffer[4]
if (strMap.has(key)) {
return strMap.get(key)
} else {
result = buffer.toString("utf8");
strMap.set(key, result)
return result
}
}
Опять же, это возможно только в сценарии, когда вы знаете, что количество уникальных строк, с которыми вы столкнетесь, довольно мало. Кроме того, поскольку все мои строки имеют длину 5, это более эффективно, чем было бы для строки большего размера ( toString()
преобразование также занимает больше времени для больших строк, так что это не значит, что оптимизация не может работать и там.
Для более широкого диапазона уникальных строк (больше, чем вы хотели бы хранить в буфере) вы можете обновить его, чтобы нарезать кэш и сохранить только, скажем, 10 000 самых последних элементов, чтобы потенциально получить меньшую оптимизацию (поскольку у вас не будет 100% кэша, а сохранение размера массива не требуется).бесплатно.
В целом, это довольно специфический вариант использования для оптимизации, но, эй, кто-то может увидеть его и найти полезным.
Комментарии:
1. Я думаю, что использование строки шаблона может быть быстрее, чем 6 конкатенаций.
2. @AKX это отличная идея, я понятия не имел, что эта функция существует в JS после работы с языком уже 8 лет. Тестирование
3. @AKX Вы имеете в виду, как:
key = String.fromCodePoint(buffer[0], buffer[1], buffer[2], buffer[3], buffer[4])
илиkey = String.raw({ raw: [buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]] })
?4. Я имел в виду
key = `${buffer[0]}${buffer[1]}${buffer[2]}${buffer[3]}${buffer[4]}`;
5. @AKX примерно идентично