Существует ли какая-либо эффективная структура для ссылки на преобразования кэшированного буфера в Node.js ?

#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 примерно идентично