在haskell中具有高性能的可变随机访问阵列/向量

时间:2013-07-26 22:33:18

标签: arrays haskell vector mutable random-access

这个关于Haskell的主题讨论了很多(例如mutable-array-implementation),但我仍然不确定需要频繁修改和随机访问数组/向量的情况的最佳实践是什么。

说一个长度为1,000,000的向量。对其进行操作涉及基于输入访问它的(小的,例如1000个)子集,并基于输入修改值。此外,这种操作重复2,000,000次。任务本身可以在纯数据结构中实现,例如列表如下,但效率非常低:

type Vect = [Int]

f :: Vect -> [[Int]] -> Vect
f x indsList = foldl g x indsList

-- g is just an example of random-access and modifications on the values.
g :: Vect -> [Int] -> Vect
g x inds = map h $ zip x [0..]
    where h (x, i) = if i `elem` inds then x !! i + 1 else x !! i

散列/映射数据结构(例如IntMap)可以用于有效的大量随机访问,但是数组/向量也应该这样做。更重要的是,仍需要通过可变结构来解决大量修改以避免存储器复制。 Haskell中是否存在可变的随机访问数组/向量?如果使用ST / IO Monads,这些控件会影响我的设置吗?

2 个答案:

答案 0 :(得分:6)

Haskell确实拥有高效的可变数组。

  • STUArray,它有相当复杂但通常只是不必要的Ix索引方法,有许多边界检查和很少的特殊优化,这使得它比理论上可能慢一点

  • 所有Data.Vector的开销都很小,大量使用流融合优化,更喜欢简单的“列表式”界面。这意味着您可以将您的示例直接转换为不可变向量,并且仍然可以获得比预期更好的性能:

    import Data.Vector.Unboxed as VU
    
    type Vect = VU.Vector Int
    
    f :: Vect -> [[Int]] -> Vect
    f x indsList = VU.foldl g x indsList
    
    
    g :: Vect -> [Int] -> Vect
    g x inds = VU.zipWith h x [0..]
        -- h is just an example of modifications on the values.
        where h x i
               | i`elem`inds   = x VU.! i + 1
               | otherwise     = x VU.! i
    

是的,您可能希望在ST monad中进行可变更新。不确定你的意思是“这些控制是否会影响性能”:一旦编译器优化了经过验证的类型安全性,就没有任何“控制”也不会出现在命令式语言中。哪个GHC可以做得很好;你可以使用Data.Vector.Unboxed非常接近C性能。总有一些不可避免的开销,但这主要与垃圾收集等问题有关,你也可以用Java来解决这些问题。

由于STIO是monad,编译器实际上可以进行一些更高级的优化,而这些优化在命令式语言中是不可能的,尽管编译器还不是那么远

许多地方都讨论了性能,尤其是数组操作的性能,例如in RWH

答案 1 :(得分:1)

来自Yarr的

Foreign UArrays是可变的,随机访问和最大快速。他们也“快而又脏”,我。即不要对每次突变操作施加冷冻/解冻样板。

缺点:几乎所有“低级别”操作都在IO下。