So ... I've used unboxed vectors (from the vector
package) preferably now without giving it much consideration. vector-th-unbox
makes creating instances for them a breeze, so why not.
Now I ran into an instance where it is not possible for me to automatically derive those instances, a data type with phantom type parameters (as in Vector (s :: Nat) a
, where s
encodes the length).
This made me think about the differences between Storable
and Unboxed
vectors. Things I figured out on my own:
Unboxed
will store eg tuples as separate vectors leading to better cache locality, by not wasting bandwidth when only one of those values is needed.Storable
will still be compiled to simple (and probably efficient) readArray#
s that return unboxed values (as evident by reading core).Storable
allows direct pointer access which allows interoperability with foreign code. Unboxed
doesn't.Storable
instances are actually easier to write by hand than Unbox
(that is Vector
and MVector
) ones.That alone doesn't make it evident to me why Unboxed
even exists, there seem to be little benefit to it. Probably I am missing something there?
Cribbed from https://haskell-lang.org/library/vector
Storable and unboxed vectors both store their data in a byte array, avoiding pointer indirection. This is more memory efficient and allows better usage of caches. The distinction between storable and unboxed vectors is subtle:
Storable
type
class.
This data is stored in malloc
ed memory, which is pinned (the garbage
collector can't move it around). This can lead to memory fragmentation, but
allows the data to be shared over the C FFI.Prim
type
class.
This data is stored in GC-managed unpinned memory, which helps avoid memory
fragmentation. However, this data cannot be shared over the C FFI.Both the Storable
and Prim
typeclasses provide a way to store a value as
bytes, and to load bytes into a value. The distinction is what type of
bytearray is used.
As usual, the only true measure of performance will be benchmarking. However, as a general guideline:
Prim
instance,
use unboxed vectors.Storable
instance, use a storable vector.There are also other issues to consider, such as the fact that boxed vectors
are instances of Functor
while storable and unboxed vectors are not.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With