Julia 的 Vector{Vector{T}} 是否连续存储在内存中?
Is Julia's Vector{Vector{T}} stored contiguously in memory?
为了激发我的问题,请考虑在 Julia 中处理元素类型 Int
的 jagged arrays(为简单起见)的情况。有两种存储方式:
- 作为
Vector{Vector{Int}}
- As
Vector{Union{Vector{Int}, Int}}
(特别是,如果希望存储足够多的 1 元素向量)
我的问题是哪个更高效/更快/更好?
要回答这个问题,除其他事项外,我需要知道每一项是如何存储在内存中的。即:
我假设 Vector{Vector{Int}}
类型的变量将被视为同构类型数组,因此我希望它连续存储在内存中,因此更 cpu-cache-friendly。我对吗?或者连续只适用于元素数据类型为原始的数组?
类型 Vector{Union{Vector{Int}, Int}}
的变量是否被视为异构数组,因此存储 而不是 连续 在记忆中?
内存中连续表示的好处与没有数组容器用于 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.
为了激发我的问题,请考虑在 Julia 中处理元素类型 Int
的 jagged arrays(为简单起见)的情况。有两种存储方式:
- 作为
Vector{Vector{Int}}
- As
Vector{Union{Vector{Int}, Int}}
(特别是,如果希望存储足够多的 1 元素向量)
我的问题是哪个更高效/更快/更好?
要回答这个问题,除其他事项外,我需要知道每一项是如何存储在内存中的。即:
我假设
Vector{Vector{Int}}
类型的变量将被视为同构类型数组,因此我希望它连续存储在内存中,因此更 cpu-cache-friendly。我对吗?或者连续只适用于元素数据类型为原始的数组?类型
Vector{Union{Vector{Int}, Int}}
的变量是否被视为异构数组,因此存储 而不是 连续 在记忆中?内存中连续表示的好处与没有数组容器用于 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.