Julia 的 Vector{Vector{T}} 是否连续存储在内存中?

Is Julia's Vector{Vector{T}} stored contiguously in memory?

为了激发我的问题,请考虑在 Julia 中处理元素类型 Intjagged arrays(为简单起见)的情况。有两种存储方式:

  1. 作为Vector{Vector{Int}}
  2. As Vector{Union{Vector{Int}, Int}}(特别是,如果希望存储足够多的 1 元素向量)

我的问题是哪个更高效/更快/更好?

要回答这个问题,除其他事项外,我需要知道每一项是如何存储在内存中的。即:

  1. 我假设 Vector{Vector{Int}} 类型的变量将被视为同构类型数组,因此我希望它连续存储在内存中,因此更 cpu-cache-friendly。我对吗?或者连续只适用于元素数据类型为原始的数组?

  2. 类型 Vector{Union{Vector{Int}, Int}} 的变量是否被视为异构数组,因此存储 而不是 连续 在记忆中?

  3. 内存中连续表示的好处与没有数组容器用于 1 元素数组成员的好处相比如何,即将它们存储为原始数据类型(Int 在这种情况下)?哪个效率更高?

如果 isbits(T) 为真,Julia 的数组将只存储未装箱的 T 类型的元素。也就是说,元素必须既是不可变的又是 pointer-free。查看元素是否立即存储的一种简单方法是分配一个未初始化的数组。未装箱(立即)值的连续数组将出现乱码:

julia> Array(Int, 3)
3-element Array{Int64,1}:
 4430901168
 4470602000
 4430901232

而 non-isbits 类型的数组将有 #undef 个指针:

julia> Array(Vector{Int}, 3)
3-element Array{Array{Int64,1},1}:
 #undef
 #undef
 #undef

想象一下如果后者 return 编辑了 Int 的一个连续块会发生什么。它怎么知道要做多大?或者一个矢量停止而下一个矢量开始的地方?这将取决于向量的大小,这是未知的。

A Vector{Union{Vector{Int}, Int}} 将类似地将其元素存储为指针;这次是因为 Julia 不知道如何解释每个内联元素(它应该像整数还是像数组一样读取内存?)。它还有一个额外的缺点,即 Julia 不再知道它 return 索引的类型。这是一个 type-instability,与仅使用 one-element 向量相比,性能肯定会 很多。

可以创建自己的参差不齐的数组类型来内联存储其元素,但要使其像普通数组一样与标准库一起使用非常棘手,因为它打破了很多关于索引如何工作的假设。你可以看看我最近的尝试:RaggedArrays.jl. You can see how I compare it to previous efforts in Issue#2.