Сравнительный анализ показывает, что библиотеке злаков
требуется в 100 раз больше времени для десериализации моей структуры данных (подробности ниже), чем для чтения тех же данных с диска:
benchmarking Read
mean: 465.7050 us, lb 460.9873 us, ub 471.0938 us, ci 0.950
std dev: 25.79706 us, lb 22.19820 us, ub 30.81870 us, ci 0.950
found 4 outliers among 100 samples (4.0%)
4 (4.0%) high mild
variance introduced by outliers: 53.460%
variance is severely inflated by outliers
benchmarking Read + Decode
collecting 100 samples, 1 iterations each, in estimated 6.356502 s
mean: 68.85135 ms, lb 67.65992 ms, ub 70.05832 ms, ci 0.950
std dev: 6.134430 ms, lb 5.607914 ms, ub 6.755639 ms, ci 0.950
variance introduced by outliers: 74.863%
variance is severely inflated by outliers
Это также подтверждается профилированием типичного использования десериализации этой структуры данных в моей программе, где 98% времени тратится на десериализацию данных, а 1% — IO
плюс основной алгоритм:
COST CENTRE MODULE %time %alloc
getWord8 Data.Serialize.Get 30.5 40.4
unGet Data.Serialize.Get 29.5 17.9
getWord64be Data.Serialize.Get 14.0 10.7
getListOf Data.Serialize.Get 10.2 12.8
roll Data.Serialize 8.2 11.5
shiftl_w64 Data.Serialize.Get 3.4 2.9
decode Data.Serialize 2.9 3.1
main Main 1.3 0.6
Структура данных, которую я десериализую, представляет собой IntMap [Triplet Atom]
, а определения типов компонентов приведены ниже:
type Triplet a = (a, a, a)
data Point = Point {
_x :: {-# UNPACK #-} !Double ,
_y :: {-# UNPACK #-} !Double ,
_z :: {-# UNPACK #-} !Double }
data Atom = Atom {
_serial :: {-# UNPACK #-} !Int ,
_r :: {-# UNPACK #-} !Point ,
_n :: {-# UNPACK #-} !Word64 }
Я использую по умолчанию IntMap
, (,,)
и[]
экземпляры, предоставленные хлопьями
, и следующие типы и экземпляры для моих пользовательских типов:
instance Serialize Point where
put (Point x y z) = do
put x
put y
put z
get = Point <$> get <*> get <*> get
instance Serialize Atom where
put (Atom s r n) = do
put s
put r
put n
get = Atom <$> get <*> get <*> get
Итак, мои вопросы:
IntMap
/[]
), чтобы ускорить десериализацию?Atom
/ Point
), чтобы ускорить десериализацию?хлопья
в Haskell, или мне следует хранить структуру данных в C-land для более быстрой десериализации (т.е.использовать mmap
)?Эти файлы, которые я десериализую, используются для субиндексов для поисковой системы, поскольку полный индекс не может поместиться в памяти целевого компьютера (который является настольным компьютером потребительского уровня), поэтому я храню каждый субиндекс на диске. и читать+декодировать субиндексы, на которые указывает исходный глобальный индекс, находящийся в памяти. Кроме того, меня не беспокоит скорость сериализации, поскольку поиск по индексу является узким местом для конечного пользователя, а текущая производительность сериализации хлопьев
удовлетворительна для создания и обновления индекса.
Редактировать:
Опробовано предложение Дона об использовании компактного триплета, и это увеличило скорость в четыре раза:
benchmarking Read
mean: 468.9671 us, lb 464.2564 us, ub 473.8867 us, ci 0.950
std dev: 24.67863 us, lb 21.71392 us, ub 28.39479 us, ci 0.950
found 2 outliers among 100 samples (2.0%)
2 (2.0%) high mild
variance introduced by outliers: 50.474%
variance is severely inflated by outliers
benchmarking Read + Decode
mean: 15.04670 ms, lb 14.99097 ms, ub 15.10520 ms, ci 0.950
std dev: 292.7815 us, lb 278.8742 us, ub 308.1960 us, ci 0.950
variance introduced by outliers: 12.303%
variance is moderately inflated by outliers
Тем не менее, он по-прежнему остается узким местом, используя в 25 раз больше времени, чем IO. Кроме того, кто-нибудь может объяснить, почему предложение Дона работает? Означает ли это, что если я переключусь на что-то другое, кроме списка (например, на массив?), это тоже может дать улучшение?
Правка №2: только что переключился на последнюю версию платформы Haskell и повторно запустил профилирование для хлопьев. Информация значительно более подробная, и я предоставил вставкуее.