Засада с эквивалентным ключом в std::unordered_map
От: Videoman Россия https://hts.tv/
Дата: 16.10.24 19:55
Оценка:
Вводные:
— С++ 17
снаружи приходят по умолчанию собранные std::unordered_map<std::string, SomeClass> (используют стандартный компаратор, это важно)

После кучи профилирования и оптимизаций бутылочного горла, сужение переместилось в место поиска по мапе, типа такого:
std::unordered_map<std::string, some_class> object; // 1
...
const auto& name = "constant string"sv; // 2
...
const auto it = object.find(std::string(name)); // 3
В строчке (3) приходится формировать строку, т.к. код создания unordered_map внешний по отношению к функции и мне не подвластен (std::less<void>, custom_allocator::is_transparent). При этом, name это всегда-всегда гарантированно константная строка. Обидно, что только для того, что бы вызвать метод поиска, приходится создавать полную строку std::string, на чем есть существенные потери тактов.

Может кто-то из спецов подскажет, можно тут что-то сделать не меняя сильно всё ?
Re: Засада с эквивалентным ключом в std::unordered_map
От: Великий Реверс google
Дата: 16.10.24 20:22
Оценка:
глобально ключ заменить ссылкой не?
ну как другой вариант делать move для find
Re[2]: Засада с эквивалентным ключом в std::unordered_map
От: Videoman Россия https://hts.tv/
Дата: 16.10.24 20:30
Оценка:
Здравствуйте, Великий Реверс, Вы писали:

ВР>глобально ключ заменить ссылкой не?

ВР>ну как другой вариант делать move для find

Если можно, приведи пример? Не понял ни первое ни второе предложение.
Re[3]: Засада с эквивалентным ключом в std::unordered_map
От: Великий Реверс google
Дата: 16.10.24 20:33
Оценка:
1)
у тебя ключ в контейнере стринг
сделай ключ стринг ссылка
стандартный или свой референс какой то придумай

2)
object.find(std::move(str));
Re[4]: Засада с эквивалентным ключом в std::unordered_map
От: Videoman Россия https://hts.tv/
Дата: 16.10.24 21:01
Оценка:
Здравствуйте, Великий Реверс, Вы писали:

ВР>1)

ВР>у тебя ключ в контейнере стринг
ВР>сделай ключ стринг ссылка
ВР>стандартный или свой референс какой то придумай

Я в условиях записал, что не могу, т.к. снаружи приходит std::unordered_map<std::string, some_class>, с std::string.

ВР>2)

ВР>object.find(std::move(str));

Этот код эквивалентен object.find(str), т.к. find на вход принимает константную ссылку.
Re: Засада с эквивалентным ключом в std::unordered_map
От: T4r4sB Россия  
Дата: 16.10.24 21:03
Оценка: +3 -1
Здравствуйте, Videoman, Вы писали:

V>Может кто-то из спецов подскажет, можно тут что-то сделать не меняя сильно всё ?


Ну такой вот калечный интерфейс у мапы, но ты не переживай, до комитета ВНИЗАПНА дошло, что они опять обосрались: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0919r2.html
Лет через 10 это войдёт в стандарт
Конкретно в твоём случае ключ всегда один и тот же , можно один раз создать строку и запомнить
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re: Засада с эквивалентным ключом в std::unordered_map
От: andyp  
Дата: 16.10.24 21:03
Оценка: +3
Здравствуйте, Videoman, Вы писали:

V>Вводные:

V>- С++ 17
V>- снаружи приходят по умолчанию собранные std::unordered_map<std::string, SomeClass> (используют стандартный компаратор, это важно)

V>После кучи профилирования и оптимизаций бутылочного горла, сужение переместилось в место поиска по мапе, типа такого:
V>std::unordered_map<std::string, some_class> object; // 1
V>...
V>const auto& name = "constant string"sv; // 2
V>...
V>const auto it = object.find(std::string(name)); // 3
V>
В строчке (3) приходится формировать строку, т.к. код создания unordered_map внешний по отношению к функции и мне не подвластен (std::less<void>, custom_allocator::is_transparent). При этом, name это всегда-всегда гарантированно константная строка. Обидно, что только для того, что бы вызвать метод поиска, приходится создавать полную строку std::string, на чем есть существенные потери тактов.


Для сравнения строк внутри unordered_map используется равенство, а не меньше, так как ключи хешируются и поиск сначала идёт по хешам ключей, а затем по ключам с равным хешем линейным просмотром. У твоей строки сначала все равно считается хеш.

Чтобы сэкономить нужен c++20, прозрачный компаратор и хешер, что для std::string скорее всего выполняется. Так что, думаю у тебя не 20е плюсы.


V>Может кто-то из спецов подскажет, можно тут что-то сделать не меняя сильно всё ?


Не спец, но может, если есть контроль над (2), там статическую строку запилить? Будет только один вызов конструктора строки при первом входе в функцию, сэкономишь один вызов конструктора при вызове find.
Re: Засада с эквивалентным ключом в std::unordered_map
От: sergii.p  
Дата: 17.10.24 10:57
Оценка: 4 (1)
Здравствуйте, Videoman, Вы писали:

V>Вводные:

V>- С++ 17
V>- снаружи приходят по умолчанию собранные std::unordered_map<std::string, SomeClass> (используют стандартный компаратор, это важно)

вроде классический костыль — завести дублирующую мапу

using map_t = std::unordered_map<std::string, SomeClass>;
map_t object;
std::unordered_map<std::string_view, map_t::iterator> ref_object;


понятно, что бред. Но если надо, значит надо.
Re[2]: Засада с эквивалентным ключом в std::unordered_map
От: andyp  
Дата: 17.10.24 11:58
Оценка: 2 (1)
Здравствуйте, T4r4sB, Вы писали:

TB>Здравствуйте, Videoman, Вы писали:


V>>Может кто-то из спецов подскажет, можно тут что-то сделать не меняя сильно всё ?


TB>Ну такой вот калечный интерфейс у мапы, но ты не переживай, до комитета ВНИЗАПНА дошло, что они опять обосрались: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0919r2.html

TB>Лет через 10 это войдёт в стандарт

Да там проблема в том, что интерфейс unordered_map пытались запилить такой же как у map. Чтобы была возможность легко заменять одно на другое в коде. А надо было для этих целей лишних адаптеров сделать имхо. Вот сейчас в с++20 введут прозрачные хешеры и компараторы, а проблема-то частично останется — ты для того, что ищешь, будешь всегда считать хеш. Платишь за то, что тебе не уперлось из-за кривого интерфейса.
Re[2]: Засада с эквивалентным ключом в std::unordered_map
От: Videoman Россия https://hts.tv/
Дата: 17.10.24 12:12
Оценка:
Здравствуйте, sergii.p, Вы писали:

SP>Здравствуйте, Videoman, Вы писали:


V>>Вводные:

V>>- С++ 17
V>>- снаружи приходят по умолчанию собранные std::unordered_map<std::string, SomeClass> (используют стандартный компаратор, это важно)

SP>вроде классический костыль — завести дублирующую мапу


SP>
SP>using map_t = std::unordered_map<std::string, SomeClass>;
SP>map_t object;
SP>std::unordered_map<std::string_view, map_t::iterator> ref_object;
SP>


Идея понятна и вполне была бы оправдана, но боюсь, у меня не наберется столько поиска, что бы перекрыть затраты на создание дополнительного хеша.
У нас это некий кусок обобщенной десериализации, где всякие JSON подобные форматы сначала десериализуются в std::unordered_map<std::string, value_class>. В другом месте, в нужный момент из std::unordered_map<std::string, value_class> происходит выдергивание типов. Фактически мне нужно один раз пройти по std::unordered_map и выдернуть оттуда значения.
Отредактировано 17.10.2024 12:13 Videoman . Предыдущая версия . Еще …
Отредактировано 17.10.2024 12:13 Videoman . Предыдущая версия .
Re[3]: Засада с эквивалентным ключом в std::unordered_map
От: watchmaker  
Дата: 17.10.24 15:13
Оценка: 28 (4) +1
Здравствуйте, andyp, Вы писали:

A> Вот сейчас в с++20 введут прозрачные хешеры и компараторы, а проблема-то частично останется — ты для того, что ищешь, будешь всегда считать хеш. Платишь за то, что тебе не уперлось из-за кривого интерфейса.


Интерфейс, конечно, кривой. Но прозрачные хэши как раз уже сейчас позволяют не считать хэш повторно от констант.

В программе ты сам делаешь выбор: считать ли хэш от string_view каждый раз, либо посчитать его однажды и положить рядом:
// строка + хэш
struct hashed_string_view: std::string_view {
    constexpr hashed_string_view(std::string_view v);
    size_t cached_hash = 0;
};

Так потратишь несколько лишних байт, но зато вычисление хэша очень будет быстрым: return this->cached_hash;. Это бывает само по себе полезно, например, когда ключи большие и хэш от них считается медленно.

И в комбинации с прозрачным хэшированием такой класс отлично работает:
struct string_hash {
    using is_transparent = void;
    constexpr std::size_t operator()(const std::string_view str) const { return my_hash_impl(str); }   // вычисляем хэш динамически
    constexpr std::size_t operator()(const hashed_string_view& str) const { return str.cached_hash; }  // достаём предпосчитанное значение
};

consteval hashed_string_view operator""_svh(const char* str, size_t len) {
    return hashed_string_view{std::string_view{str, len}};
}


Теперь, если использовать string_hash в качестве хэшера для мапы, то от констант значение хэша будет посчитано сразу:
std::unordered_multimap<std::string, ValueType, string_hash, std::equal_to<>> map;

auto it = map.find("key"_svh);
Демо и сравнение.

A> проблема-то частично останется


Хотя упрёк справедливый, потому из коробки не работает:
  1. В старом коде нужно включать поддержку прозрачности явно из-за параноидальной обратной совместимости;
  2. Готового mixin-класса для кэширования хэшей в стандартной библиотеки нет;
  3. Хэш функцию тоже нужно подставлять свою, из-за возможности рандомизации std::hash<string_view>, из-за чего её в общем случае нельзя вычислять от константных литералов во время компиляции (и не важно, что никто этой возможностью не пользуется) .
Каждый пункт решается в одну-две строчки, но этого уже достаточно, чтобы куча кода так и оставалось работать с неэффективными значениями по умолчанию.
Отредактировано 17.10.2024 18:35 watchmaker . Предыдущая версия .
Re[3]: Засада с эквивалентным ключом в std::unordered_map
От: T4r4sB Россия  
Дата: 17.10.24 15:15
Оценка:
Здравствуйте, andyp, Вы писали:



A>Да там проблема в том, что интерфейс unordered_map пытались запилить такой же как у map. Чтобы была возможность легко заменять одно на другое в коде.


Так у мапы тоже непонятно, почему нельзя делать поиск по стрингвью без конструирования строки.
А подсчет хеша на фоне лишних созданий строки — считай бесплатен.

Так что если это допустимо в проекте — то использовать альтернативную хешмапу. Если не требуется чтоб элементы сохраняли свой адрес, то наверное любая альтернативная мапа будет быстрее стдшной
Нет такой подлости и мерзости, на которую бы не пошёл gcc ради бессмысленных 5% скорости в никому не нужном синтетическом тесте
Re[4]: Засада с эквивалентным ключом в std::unordered_map
От: so5team https://stiffstream.com
Дата: 17.10.24 16:30
Оценка: +1
Здравствуйте, T4r4sB, Вы писали:

A>>Да там проблема в том, что интерфейс unordered_map пытались запилить такой же как у map. Чтобы была возможность легко заменять одно на другое в коде.


TB>Так у мапы тоже непонятно, почему нельзя делать поиск по стрингвью без конструирования строки.


Можно начиная с С++14 (https://en.cppreference.com/w/cpp/container/map/find).
Нужно только std::less<> в качестве компаратора не забывать явно вписывать.

А вот с хэш-таблицами нужно ждать новых стандартов.
Re[4]: Засада с эквивалентным ключом в std::unordered_map
От: andyp  
Дата: 17.10.24 17:42
Оценка:
Здравствуйте, watchmaker, Вы писали:

со всем согласен!

W>
  • Готового mixin-класса для кэширования хэшей в стандартной библиотеки нет;

    Ну да, это плохо. У меня всегда есть опасения, что в контейнере окажется другой хешер
  • Re[3]: Засада с эквивалентным ключом в std::unordered_map
    От: · Великобритания  
    Дата: 17.10.24 21:50
    Оценка: +2
    Здравствуйте, Videoman, Вы писали:

    V> У нас это некий кусок обобщенной десериализации, где всякие JSON подобные форматы сначала десериализуются в std::unordered_map<std::string, value_class>. В другом месте, в нужный момент из std::unordered_map<std::string, value_class> происходит выдергивание типов. Фактически мне нужно один раз пройти по std::unordered_map и выдернуть оттуда значения.

    А зачем вообще тогда sv? Константы инициализируются только один раз, этим и пользуемся:
    const auto& name = std::string("constant string");
    ...
    const auto it = object.find(name);


    Ещё как вариант: вместо создания новой строки — создать её один раз, зарезервировав размер по максимуму, и потом переприсваивать. Как я понимаю, основные тормоза обычно идут не на копирование байтов, а на выделение-удаление динамической памяти из кучи.
    avalon/3.0.0
    но это не зря, хотя, может быть, невзначай
    гÅрмония мира не знает границ — сейчас мы будем пить чай
    Re[3]: Засада с эквивалентным ключом в std::unordered_map
    От: landerhigh Пират  
    Дата: 18.10.24 14:46
    Оценка:
    Здравствуйте, Videoman, Вы писали:

    V>Идея понятна и вполне была бы оправдана, но боюсь, у меня не наберется столько поиска, что бы перекрыть затраты на создание дополнительного хеша.

    V>У нас это некий кусок обобщенной десериализации, где всякие JSON подобные форматы сначала десериализуются в std::unordered_map<std::string, value_class>. В другом месте, в нужный момент из std::unordered_map<std::string, value_class> происходит выдергивание типов. Фактически мне нужно один раз пройти по std::unordered_map и выдернуть оттуда значения.

    В таком случае возникает закономерный вопрос — а существует ли оно, это бутылочное горлышко, на самом деле? Или видно исключительно в профайлере?
    Re: Засада с эквивалентным ключом в std::unordered_map
    От: Ip Man Китай  
    Дата: 20.10.24 14:45
    Оценка:
    https://www.cppstories.com/2021/heterogeneous-access-cpp20/
    Re[4]: Засада с эквивалентным ключом в std::unordered_map
    От: Videoman Россия https://hts.tv/
    Дата: 20.10.24 17:36
    Оценка:
    Здравствуйте, ·, Вы писали:

    ·>А зачем вообще тогда sv? Константы инициализируются только один раз, этим и пользуемся:


    Получается, в рамках С++17, это единственный вариант без просадки производительности. Но пользоваться константами не очень удобно, думал может быть есть варианты получше.
    Re[5]: Засада с эквивалентным ключом в std::unordered_map
    От: · Великобритания  
    Дата: 21.10.24 09:40
    Оценка: +2
    Здравствуйте, Videoman, Вы писали:

    V>·>А зачем вообще тогда sv? Константы инициализируются только один раз, этим и пользуемся:

    V>Получается, в рамках С++17, это единственный вариант без просадки производительности. Но пользоваться константами не очень удобно, думал может быть есть варианты получше.
    А в чём недостатки этого варианта?

    А вообще, конечно, смешно. Парсим охрененно избыточный медленный json и экономим на спичках, считая байты... Хочешь перформанс — бери SBE или protobuf хотя бы.
    но это не зря, хотя, может быть, невзначай
    гÅрмония мира не знает границ — сейчас мы будем пить чай
    Re[6]: Засада с эквивалентным ключом в std::unordered_map
    От: watchmaker  
    Дата: 21.10.24 14:51
    Оценка:
    Здравствуйте, ·, Вы писали:

    ·>А вообще, конечно, смешно. Парсим охрененно избыточный медленный json и экономим на спичках, считая байты... Хочешь перформанс — бери SBE или protobuf хотя бы.


    Забавно, но если сравнивать самые быстрые парсеры, то simdjson выигрывает у protobuf, даже несмотря на то, что парсить ему приходится куда более объёмный сериализованный текст.
    Бинарный формат protobuf отравлен varint'ами — в нём для чтения очередного поля нужно разобрать предыдущее — и ни у кого не получается это место хорошо на уровне инструкций распараллелить.

    Но, совет всё равно хороший, так как и другое, скорее всего, будет работать на порядок быстрее чем самодельный парсер с std::unordered_map внутри.
    Re[7]: Засада с эквивалентным ключом в std::unordered_map
    От: · Великобритания  
    Дата: 21.10.24 14:56
    Оценка:
    Здравствуйте, watchmaker, Вы писали:

    W>·>А вообще, конечно, смешно. Парсим охрененно избыточный медленный json и экономим на спичках, считая байты... Хочешь перформанс — бери SBE или protobuf хотя бы.

    W>Забавно, но если сравнивать самые быстрые парсеры, то simdjson выигрывает у protobuf, даже несмотря на то, что парсить ему приходится куда более объёмный сериализованный текст.
    Вроде SBE затачивался под скорость и latency.

    W>Бинарный формат protobuf отравлен varint'ами — в нём для чтения очередного поля нужно разобрать предыдущее — и ни у кого не получается это место хорошо на уровне инструкций распараллелить.

    Любопытно. А чем json лучше в этом? Там вроде каждое поле таким образом "отравлено".

    W>Но, совет всё равно хороший, так как и другое, скорее всего, будет работать на порядок быстрее чем самодельный парсер с std::unordered_map внутри.

    Именно. И я почему-то уверен, что он перформанс микробенчмарком на map.find вместо замера общего перформанса обработки запроса включая парсинг и т.п.
    но это не зря, хотя, может быть, невзначай
    гÅрмония мира не знает границ — сейчас мы будем пить чай
    Re[8]: Засада с эквивалентным ключом в std::unordered_map
    От: watchmaker  
    Дата: 21.10.24 16:47
    Оценка: 18 (4) +1
    Здравствуйте, ·, Вы писали:

    W>>Бинарный формат protobuf отравлен varint'ами — в нём для чтения очередного поля нужно разобрать предыдущее — и ни у кого не получается это место хорошо на уровне инструкций распараллелить.

    ·>Любопытно. А чем json лучше в этом? Там вроде каждое поле таким образом "отравлено".

    Тем что в нём структура документа описывается символами []{}",: , которые в любом контексте выглядят одинаково. И у CPU есть соответствующие инструкции, которые, например, берут длинную строку и возвращают битовую маску позиций, где в ней находятся эти символы.
    После чего определение границ структур сводится к поиску парных скобок. То есть для '"' нужно найти парную '"' — и всё что между ними — это строка.
    В современных архитектурах (x86,arm,risc-v) даже есть инструкция для таких операций с битами.
    Конечно, есть случаи экранированных '\"' внутри строки, но это точно так же сводится к получению битовой маски вхождения символа '\' и нескольким побитовым операциям.

    Можно примерно схему в https://arxiv.org/abs/1902.08318 почитать.


    А в varint нужно каждый раз смотреть на старший бит в байте на предмет того, является ли продолжением предыдущего элемента или уже новым. Но при этом размеры сообщений, строк и packed-массивов кодируются длиной. То есть для них уже не работает трюк с выделением маски старших битов и нахождением в нём групп единиц, разделённых нулями через умножение полиномов, так как неизвестно находился ли бит внутри строки или нет. А чтобы это узнать — нужно прочитать длину строки. И мы вынуждены либо использовать последовательный разбор, либо пытаться сделать разбор со всех позиций сразу, чтобы потом выбрать настоящую. Но и то и другое скорости не добавляет.
    Отредактировано 21.10.2024 21:01 watchmaker . Предыдущая версия . Еще …
    Отредактировано 21.10.2024 19:02 watchmaker . Предыдущая версия .
    Re[6]: Засада с эквивалентным ключом в std::unordered_map
    От: Videoman Россия https://hts.tv/
    Дата: 21.10.24 17:54
    Оценка:
    Здравствуйте, ·, Вы писали:

    ·>А вообще, конечно, смешно. Парсим охрененно избыточный медленный json и экономим на спичках, считая байты... Хочешь перформанс — бери SBE или protobuf хотя бы.


    Вообще JSON парсится влет и быстро, с ним нет проблем. Проблема в промежуточном слое, который был сделан в угоду гибкости (ну или из-за отсутствия до сих пор в C++ рефлексии) и тормозит уже десериализация во внутренние типы. Скорость сейчас устраивает, просто хотел подточить углы сделать запас.
    Re: Засада с эквивалентным ключом в std::unordered_map
    От: Videoman Россия https://hts.tv/
    Дата: 21.10.24 17:58
    Оценка:
    Кстати по ходу обсуждения появился ещё один вопрос: если начать плавно переходить на С++20, то как с полнотой его поддержки в GCC сейчас обстоят дела?

    Когда я фиксировал стандарт в прошлый раз на С+17, то обнаружил, что MSVC нормально поддерживал С++17, почти полностью, CLang — тоже, а вот с GCC были проблемы, приходилось ставить 10-ю или даже 11-ю версию. А как сейчас дела с 20-м стандартом?
    Re[2]: Засада с эквивалентным ключом в std::unordered_map
    От: Великий Реверс google
    Дата: 21.10.24 18:09
    Оценка:
    если как марти будешь сидеть на каком нибудь старом гцц 7.2
    то да
    проблем много
    начиная с самой главной
    с++20 он в этой версии только начинал поддерживать

    а если поставить самый последний гцц
    то проблем нет
    с++26 по чуть чуть добавляют
    Re[3]: Засада с эквивалентным ключом в std::unordered_map
    От: Videoman Россия https://hts.tv/
    Дата: 21.10.24 18:32
    Оценка:
    Здравствуйте, Великий Реверс, Вы писали:

    ВР>если как марти будешь сидеть на каком нибудь старом гцц 7.2


    Не знаю как там с 7.2, но на 9-м я столкнулся с тем, что не были реализованы некоторые части стандартной библиотеки 17-го стандарта.
    Re[9]: Засада с эквивалентным ключом в std::unordered_map
    От: · Великобритания  
    Дата: 21.10.24 19:24
    Оценка:
    Здравствуйте, watchmaker, Вы писали:

    w> Конечно, есть случаи экранированных '\"' внутри строки, но это точно так же сводится к получению битовой маски вхождения символа '\t' и нескольким побитовым операциям.

    Спасибо, интересно.
    А как с числами быть? Надо уметь конвертировать десятичное представление в int, да ещё и 1000000 может быть записано как 1.0E6.

    w> Можно примерно схему в https://arxiv.org/abs/1902.08318 почитать.

    Гы, деньги хотят.

    w> А чтобы это узнать — нужно прочитать длину строки. И мы вынуждены либо использовать последовательный разбор, либо пытаться сделать разбор со всех позиций сразу, чтобы потом выбрать настоящую. Но и то и другое скорости не добавляет.

    Прикольно. Т.е. я правильно понял, что закрывающий символ, даже с учётом экранирования, можно найти быстрее, чем сразу же прочитать длину?! Совершенно контринтуитивно.
    avalon/3.0.0
    но это не зря, хотя, может быть, невзначай
    гÅрмония мира не знает границ — сейчас мы будем пить чай
    Re[4]: Засада с эквивалентным ключом в std::unordered_map
    От: Великий Реверс google
    Дата: 21.10.24 20:03
    Оценка:
    https://en.cppreference.com/w/cpp/compiler_support/17
    https://en.cppreference.com/w/cpp/compiler_support/20
    Re[9]: Засада с эквивалентным ключом в std::unordered_map
    От: landerhigh Пират  
    Дата: 21.10.24 21:09
    Оценка:
    Здравствуйте, watchmaker, Вы писали:

    W>Можно примерно схему в https://arxiv.org/abs/1902.08318 почитать.


    Спасибо, интересно.

    Правда, я не уверен, что так уж корректно измерять скорость работы парсера в гигабайтах в секунду.

    Согласен с тем, что varint может быть проблемой. Но, для пересылки одного 32-битного int потребуется 6 байтов максимум. В случае json — это до десяти байтов плюс разделители, итого 11 или 12. В два раза больше.
    Но это вырожденный случай, число "800" (16-битный int) потребует 3 байтов в protobuf и тех же трех в json плюс один или два разделителя.
    но в случае с protobuf, это уже включает идентификатор поля, а в случае в json идентификатор поля — это отдельная строка черт его знает какой длины, для которой еще нужно будет посчитать хеш...
    Re[10]: Засада с эквивалентным ключом в std::unordered_map
    От: landerhigh Пират  
    Дата: 21.10.24 21:11
    Оценка: +1
    Здравствуйте, ·, Вы писали:

    w>> Можно примерно схему в https://arxiv.org/abs/1902.08318 почитать.

    ·>Гы, деньги хотят.

    У меня получилось PDF скачать.
    Re[10]: Засада с эквивалентным ключом в std::unordered_map
    От: watchmaker  
    Дата: 22.10.24 00:04
    Оценка:
    Здравствуйте, landerhigh, Вы писали:


    L>Правда, я не уверен, что так уж корректно измерять скорость работы парсера в гигабайтах в секунду.


    Да нормально — это же метрика для сравнения разных реализаций json парсеров между собой. У них цель быстрее распарсить готовый json-документ, а не соревноваться с парсерами альтернативных форматов сериализации.



    L> Но, для пересылки одного 32-битного int потребуется 6 байтов максимум. В случае json — это до десяти байтов плюс разделители, итого 11 или 12. В два раза больше.

    L>Но это вырожденный случай

    Ага, есть такое наблюдение, что выгодно оптимизировать не вырожденный, а средний случай. И не случай битого документа (где код обработки ошибки может быть не таким быстрым), и не случай валидного, но странного входа (например, когда у float сотня цифр после запятой записана), так как такие документы считай что и не встречаются, если не созданы специально.

    L>но в случае с protobuf, это уже включает идентификатор поля, а в случае в json идентификатор поля — это отдельная строка черт его знает какой длины


    Понятно, что в среднем json более «рыхлый».
    Тем удивительнее, что simdjson умудряется оказываться быстрее даже при пересчёте на размер исходных данных. Выигрыш сильно меньше, но парадоксально, что он вообще есть.
    Re[10]: Засада с эквивалентным ключом в std::unordered_map
    От: watchmaker  
    Дата: 22.10.24 00:31
    Оценка: +1
    Здравствуйте, ·, Вы писали:

    ·>А как с числами быть?


    Конвертировать медленно и мучительно. Какие-то части парсера будут медленнее работать из-за текстовой природы формата.

    w>> А чтобы это узнать — нужно прочитать длину строки. И мы вынуждены либо использовать последовательный разбор, либо пытаться сделать разбор со всех позиций сразу, чтобы потом выбрать настоящую. Но и то и другое скорости не добавляет.

    ·>Т.е. я правильно понял, что закрывающий символ, даже с учётом экранирования, можно найти быстрее, чем сразу же прочитать длину?!

    Скорее выигрышь в том, что одной операцией можно найти все открывающие и закрывающие символы в целом блоке данных, где таких последовательностией может быть больше одной.
    А с явной длиной нужно сначала её прочитать, и лишь потом сместиться в потоке на указанное смещение к началу следующей последовательности. Тут между ними возникает зависимость, мешающая параллелизму.
    Ну и свою роль ещё играет не самый удачный выбор способа записи самих varint'ов и тегов в protobuf.
    Re[11]: Засада с эквивалентным ключом в std::unordered_map
    От: landerhigh Пират  
    Дата: 22.10.24 07:08
    Оценка: +1
    Здравствуйте, watchmaker, Вы писали:

    L>>Правда, я не уверен, что так уж корректно измерять скорость работы парсера в гигабайтах в секунду.

    W>Да нормально — это же метрика для сравнения разных реализаций json парсеров между собой. У них цель быстрее распарсить готовый json-документ, а не соревноваться с парсерами альтернативных форматов сериализации.

    Для сравнения json парсеров между собой — да. Но подобная метрика не подходит, если хочется проверить, не выгоднее ли использовать simdjson, нежели protobuf.

    W>Понятно, что в среднем json более «рыхлый».

    W>Тем удивительнее, что simdjson умудряется оказываться быстрее даже при пересчёте на размер исходных данных. Выигрыш сильно меньше, но парадоксально, что он вообще есть.

    Понятное дело, что в целом нужно рассматривать не только производительность парсера, но и в целом размер данных, пересылаемых по сети. Тут в общем binary протоколы будут в выигрыше
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.