спрошу.
Задача: есть данные (структура такая же как и в БД: несколько столбцов и много строчек), они хранятся в файле, у которого свой формат, надо их обработать.
Формат файла такой: сначала идёт схема/описание "столбцов" (тип данных, количество байт, которое нужно на хранение, название "столбца"), а далее идут непосредственно данные, которые надо парсить исходя из описания (схемы). И написать парсер было легко (пришлось, конечно, дублировать тип данных и сами данные).
enum T {
Int32(i32),
Float(f32),
Double(f64),
...
}
enum TType {
Int32,
Float,
Double,
...
}
Однако в парсере при каждом считывании ячейки нужно знать тип (берётся из схемы) и по нему определять, сколько байт надо считать и каким образом превращать байтики (например, для Int32 это будет i32::from_le_bytes, для Float это будет f32::from_le_bytes). И из-за этого приходится делать что-то такое:
match ttype {
TType::Int32 => ...,
TType::Float => ...,
TType::Double => ...,
...
}
И это создаёт слишком много branch instructions (надеюсь, я правильно использую термин). Можно ли от них избавиться?
Вообще исходная идея была такова: каким-то чудом парсить данные (после того как мы знаем схему), не делая pattern matching (в общем, избавиться от branch instructions). Это вообще можно реализовать?
Пока я писал этот текст, я понял, что можно было бы использовать HashMap (по типу сразу достать функцию, которую потом вызвать)
матч и так может скомпилится в хэшфуннкцию или дерево, как оптимизация
Если тебе такое подойдёт можешь посмотреть на поколоночное хранение, т е чтобы у тебя сначала лежали все значение одной колонки, потом все значения другой и тд, тогда тип можно будет проверять один раз на столбец. Больше можно посмотреть в контексте колоночных СУБД, там как всегда, свои плюсы свои минусы
Конечно, я не смогу изменить формат данных, но читать по колонкам данные я смогу
Надо смотреть, если файл большой то может так получиться что ты его несколько раз читаешь, и если он в page cache операционки не поместится то ещё и прям с диска будет несколько раз данные запрашивать, и это будет сильно дольше чем ещё один if
Ещё одна мысль, у тебя же схема на протяжении файла не меняется? Т е ты можешь сразу при чтении схемы сопоставить номер поля и соответствующую функцию Парсинга, т е на каждую строчку ветвления не будет
Да, схема одна и та же. А сопоставить можно с помощью того же HashMap?
Должно и вектора хватить, номер поля в схеме -> индекс в векторе
можно даже при парсинге прям по этому вектору итерироваться
А потом лукапаться по хешмапе дороже будет)
Нафига и зачем хэшмапа, если матч сделан практически в стиле switch-case, где у него и так будет наиболее оптимальная табличка? Без всякого хэширования, лазания в кучу и проверок наличия индекса с двойными лукапами.
и это тоже да, хешировать инты по идее должно быть дешево, но все равно дороже чем просто индекс
Может, я что-то не так делаю или не понимаю, но тут есть переходы: https://godbolt.org/z/hE3xzo3Md (14 строчка)
Наверное, можно было бы сделать как-то так: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ee3a429ec2cb50764eae681f998c771c
Да, действительно... Это всё из-за переполнений (упростил функции, чтобы точно не было переполнений и всё ок. Паттерн матчинг быстрый стал)
Обсуждают сегодня