提问人:Bots Fab 提问时间:2/2/2021 最后编辑:trincotBots Fab 更新时间:6/13/2021 访问量:216
如何将任意长度的 Vec<T> 的所有条目加载到堆栈中?
How can I load all entries of a Vec<T> of arbitrary length onto the stack?
问:
我目前正在使用向量,并试图确保我在堆栈上拥有本质上是我的向量数组的内容。我无法调用,因为我在我的 .这可能吗?Vec::into_boxed_slice
Vec
在阅读了关于如何实现 Vec
的 Rustonomicon 之后,它似乎跨越了堆上的指针,在每个条目处取消引用。我想将堆中的条目分块到堆栈中以便快速访问。Vec
答:
5赞
Shepmaster
2/2/2021
#1
您可以在 nightly Rust 中使用该功能:unsized_locals
#![feature(unsized_locals)]
fn example<T>(v: Vec<T>) {
let s: [T] = *v.into_boxed_slice();
dbg!(std::mem::size_of_val(&s));
}
fn main() {
let x = vec![42; 100];
example(x); // Prints 400
}
另请参阅:
我无法调用,因为我在我的
Vec::into_boxed_slice
Vec
当然可以。
Vec
[...] 似乎跨过堆上的指针,在每个条目处取消引用
访问 a 中的每个成员都需要内存取消引用。访问数组中的每个成员都需要内存取消引用。这里的速度没有实质性的区别。Vec
用于快速访问
我怀疑这不会比直接访问中的数据更快。事实上,如果它更慢,我不会感到惊讶,因为你正在复制它。Vec
评论
0赞
Bots Fab
2/2/2021
在我的印象中,从堆栈中取消引用会比堆的数据结构更快。我正在懒惰地实现一种算法,该算法在处理时有时间异步在内存中分块,所以认为这可能会节省一些时间。谢谢,我无法让编译器允许我.into_boxed_slice,因为 [Cell<T>] 没有实现 Sized 特征。我认为这是由于由于 T 已调整大小后没有明确声明 [Cell<T>; n]。我会再试一次,每晚阅读。
1赞
Masklinn
2/2/2021
@BotsFab初始 deref 会更慢,因为堆栈在缓存中,而堆位置不在缓存中,但加载 vec 会以任何一种方式缓存它。除非通过在堆栈上加载缓存,否则您会使缓存膨胀,并且可能使代码本身膨胀(不确定未调整大小的局部变量,但我知道在 C VLA 中会导致绝对垃圾代码生成)。
0赞
Bots Fab
2/2/2021
@Masklinn VLA 相对较小,并且非常适合缓存。它是一种树状结构,其中来自给定节点的边缘被分块到堆栈上,我计划在配置中限制边缘,或者在必要时自动适应缓存行)。到目前为止,这是一个边缘情况,它可能偏离了主题,但似乎正在引起合理的兴趣。这个细节很重要,因为它是一种可扩展的 ML 算法(以及我对速度的情感价值)。
1赞
Masklinn
2/2/2021
@BotsFab如果它们适合缓存,它们将与它们已经拥有的 Vec 一样适合,这充其量应该没有区别。动态堆栈分配的问题在于编译器生成的代码低于标准。
1赞
Masklinn
2/2/2021
TBF 我不知道这是否与 VLA 有相同的问题,但我确实知道 VLA 最终被剥离到 linux 内核(以及各种其他代码库)之外的原因之一是它们会导致非常糟糕的代码。
评论
Vec
T
Vec
的数据始终是连续的(“连续的可增长数组类型”),这在局部性方面是尽可能好的。您似乎混淆了数据类型“堆栈”和“堆”以及内存区域“堆栈”和“堆”。我鼓励你研究其中的区别;我认为这将把事情弄清楚。Vec
Vec