首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在Haskell中进行快速数据反序列化

如何在Haskell中进行快速数据反序列化
EN

Stack Overflow用户
提问于 2012-06-06 01:59:42
回答 1查看 2.1K关注 0票数 21

基准测试显示,cereal库反序列化我的数据结构(详细信息如下)所需的时间是从驱动器中读取相同数据所需时间的100倍:

代码语言:javascript
复制
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加上核心算法:

代码语言:javascript
复制
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],组件类型的定义如下:

代码语言:javascript
复制
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 }

我使用cereal提供的默认IntMap(,,)[]实例,以及以下类型和自定义类型的实例:

代码语言:javascript
复制
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

所以我的问题是:

  1. 为什么反序列化总体上这么慢?
  2. 是否有方法更改我的数据结构(即IntMap/[])以使反序列化更快?
  3. 是否有方法更改我的数据类型(即Atom/Point)以使反序列化更快?
  4. 在Haskell中是否有比cereal更快的替代方案,或者我是否应该将数据结构存储在C-land中以进行更快速的反序列化(即使用Haskell

我正在反序列化的这些文件用于搜索引擎的子索引,因为目标计算机(消费级台式机)的内存无法容纳完整的索引,所以我将每个子索引存储在磁盘上,并对驻留在内存中的初始全局索引所指向的子索引进行read+decode。此外,我不关心序列化速度,因为搜索索引是最终用户的瓶颈,而且cereal当前的序列化性能对于生成和更新索引是令人满意的。

编辑:

尝试了Don提出的使用节省空间的三元组的建议,速度提高了四倍:

代码语言:javascript
复制
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

但是,它仍然是瓶颈,占用的时间是IO的25倍。另外,有人能解释一下Don的建议为什么有效吗?这是否意味着如果我切换到列表以外的其他类型(比如数组)?它可能也会带来进步?

编辑#2:刚刚切换到最新的Haskell平台,并重新运行了谷类的分析。信息要详细得多,我提供了它的hpaste

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-06-07 20:00:03

好的。用建议的摘要来回答这个问题。对于数据的快速反序列化:

  • 使用cereal (严格字节串输出)或binary (惰性字节串输出)
  • 确保使用-O2编译,因为这些库依赖内联来消除开销
  • 使用密集数据类型,例如用未打包的专用表单替换多态元组。
  • 避免将数据类型转换为列表以序列化它们。如果你有字节串,这就会得到处理。对于未打包的数组类型,您通常会获得非常快的IO,但值得仔细检查instances
  • You是否能够将mmap'd IO
  • 用于双重数据考虑更高效的双读取器。
  • 使用针对性能进行了调整的现代数组和容器类型,具有较新的GHC版本。
票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10902405

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档