Julia的矢量{Vector {T}}连续存储在内存中吗?

问题描述:

为了激励我的问题,请考虑处理Julia中的元素类型为Intjagged arrays(为了简单起见)的情况。有两种方法来存储它们:Julia的矢量{Vector {T}}连续存储在内存中吗?

  1. 作为Vector{Vector{Int}}
  2. 作为Vector{Union{Vector{Int}, Int}}(尤其是,如果一个人希望以存储足够大的数1-要素矢量的)

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

为了回答这个问题,我需要知道每个内存是如何存储在内存中的。即:

  1. 我假定一个类型Vector{Vector{Int}}的变量,将被认为是均匀的型阵列,因此,我希望它被存储连续在存储器,并且这样更CPU-的cache友善。我对吗?或者连续性仅适用于元素的数据类型为原始的数组?

  2. 一个 Vector{Union{Vector{Int}, Int}}类型考虑异质阵列的
  3. 将可变的,并且这样存储的在存储器中连续

  4. 将存储器中连续表示的好处与没有数组容器的1元素数组成员相比较的好处,即将它们存储为基本数据类型(在这种情况下为Int)?哪一个可以提高效率?

+0

引用将被连续存储,而不是所有的数据。我不认为工会或非工会类型会产生实质性差异。 – pvg

Julia的阵列只会T型拆箱如果isbits(T)是真实的商店元素。也就是说,这些元素必须是不可变的和无指针的。查看元素是否被立即存储的简单方法是分配一个未初始化的数组。拆箱(即时)值的连续阵列将有乱码:

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

而非isbits类型的数组将有#undef指针:

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

想象会发生什么,如果是后者返回的一个连续的大块Int s。它如何知道它有多大?或者一个矢量停止,下一个开始?这将取决于向量的大小,这还不知道。

A Vector{Union{Vector{Int}, Int}}将类似地将其元素存储为指针;这一次是因为Julia不知道如何解释每一个内联元素(是否应该像整数或像数组一样读取内存?)。它还有另一个缺点,就是Julia不知道它会从索引返回什么类型。这是一种类型不稳定性,并且肯定会比仅使用一个元素向量的性能更差。

可以创建自己的不规则数组类型来存储它的内联元素,但是它使标准库像普通数组一样工作是非常棘手的,因为它打破了很多有关索引工作原理的假设。你可以看看我最近的尝试:RaggedArrays.jl。您可以看到我如何将其与Issue#2中的以前工作进行比较。

+1

如果它适合应用程序,也请看'SparseMatrix'。非零元素被连续存储(列是连续的)。因此,索引会很快。如果你有的元素都是非零的(或者可以这样做),这将很好地工作。 –

+0

另请注意,即使RaggedArray的元素是连续存储的,它仍然需要从辅助数组中查找其索引(在大多数情况下)。我没有对它进行基准测试或优化,所以如果存在'Vector {Vector {T}}'更快的情况,我不会感到惊讶。 –