【问题标题】:Is Julia's Vector{Vector{T}} stored contiguously in memory?Julia 的 Vector{Vector{T}} 是否连续存储在内存中?
【发布时间】:2016-04-17 21:30:22
【问题描述】:

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

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

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

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

  1. 我认为 Vector{Vector{Int}} 类型的变量将被视为同类类型数组,因此我希望它连续存储在内存中,因此更多cpu 缓存友好。我对吗?还是连续性只适用于元素数据类型为原始的数组?

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

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

【问题讨论】:

  • 引用将连续存储,而不是所有数据。我不认为联合或非联合类型会产生任何实质性差异。

标签: arrays multidimensional-array julia jagged-arrays ragged


【解决方案1】:

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

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

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

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

想象一下如果后者返回一个连续的Ints 块会发生什么。它怎么知道做多大?或者一个向量在哪里停止而下一个向量在哪里开始?这取决于向量的大小,目前尚不清楚。

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

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

【讨论】:

  • 如果它适合应用程序,还请查看SparseMatrix。非零元素连续存储(列是连续的)。因此,索引会很快。如果你拥有的元素都是非零的(或者可以这样),这会很好地工作。
  • 还要注意,即使 RaggedArray 的元素是连续存储的,它仍然需要从辅助数组中查找其索引(在大多数情况下)。我没有对它进行彻底的基准测试或优化,所以如果在某些情况下Vector{Vector{T}} 更快,我一点也不感到惊讶。
猜你喜欢
  • 2014-03-27
  • 1970-01-01
  • 2021-12-21
  • 2020-05-21
  • 1970-01-01
  • 2014-02-14
  • 2017-03-21
  • 2011-09-21
  • 2016-01-12
相关资源
最近更新 更多