14

所以......我vector现在最好使用未装箱的向量(来自包装),而没有给予太多考虑。vector-th-unbox为它们创建实例变得轻而易举,为什么不呢。

现在我遇到了一个实例,我无法自动派生这些实例,这是一种带有幻像类型参数的数据类型(如Vector (s :: Nat) a,其中s编码长度)。

这让我想到了StorableUnboxed向量之间的区别。我自己想出来的事情:

  • Unboxed将例如元组存储为单独的向量,从而在只需要其中一个值时不浪费带宽,从而导致更好的缓存局部性。
  • Storable仍将被编译为readArray#返回未装箱值的简单(并且可能是有效的)s(如阅读核心所示)。
  • Storable允许直接指针访问,这允许与外部代码的互操作性。Unboxed没有。
  • [编辑]实例实际上比(即和)Storable更容易手写。UnboxVectorMVector

仅这一点并不能让我明白为什么Unboxed甚至存在,它似乎没有什么好处。可能我在那里遗漏了什么?

4

2 回答 2

21

抄自https://haskell-lang.org/library/vector

可存储和未装箱的向量都将它们的数据存储在一个字节数组中,避免了指针间接。这更节省内存并允许更好地使用缓存。可存储向量和未装箱向量之间的区别很微妙:

  • 可存储向量需要作为Storable类型类实例的数据。此数据存储在malloced 内存中,该内存已固定(垃圾收集器无法移动它)。这可能会导致内存碎片,但允许通过 C FFI 共享数据。
  • 未装箱的向量需要作为Prim类型类实例的数据。此数据存储在 GC 管理的未固定内存中,这有助于避免内存碎片。但是,这些数据不能通过 C FFI 共享。

Storable和类型类都Prim提供了一种将值存储为字节并将字节加载到值中的方法。区别在于使用的是什么类型的字节数组。

像往常一样,唯一真正衡量性能的方法是基准测试。但是,作为一般准则:

  • 如果您不需要将值传递给 C FFI,并且您有一个Prim实例,请使用未装箱的向量。
  • 如果您有Storable实例,请使用可存储的向量。
  • 否则,使用盒装向量。

还有其他问题需要考虑,例如装箱向量是Functor可存储向量的实例,而未装箱向量则不是。

于 2016-10-23T02:29:03.763 回答
0

另一个区别是内存开销:

根据我的测量:

  • Data.Vector.Storable.Vector Int有 64 字节开销
  • Data.Vector.Unboxed.Vector Int有 48 字节的开销。

资源:

于 2021-03-28T01:03:00.503 回答