gpt4 book ai didi

rust - 将数据移动到 Rc/Arc 是否总是将其从堆栈复制到堆?

转载 作者:行者123 更新时间:2023-12-04 11:29:21 29 4
gpt4 key购买 nike

看下面这个简单的例子:

use std::rc::Rc;

struct MyStruct {
a: i8,
}

fn main() {
let mut my_struct = MyStruct { a: 0 };
my_struct.a = 5;
let my_struct_rc = Rc::new(my_struct);

println!("my_struct_rc.a = {}", my_struct_rc.a);
}
Rc的官方文档说:

The type Rc<T> provides shared ownership of a value of type T,allocated in the heap.


理论上是清楚的。但是,首先 my_struct没有立即包装成 Rc ,其次 MyStruct是一个非常简单的类型。我可以在这里看到 2 个场景。
  • my_struct移入 Rc内存内容从堆栈中复制到堆中。
  • 编译器能够解决 my_struct将移入Rc ,所以它从一开始就把它放在堆上。

  • 如果数字 1 为真,那么可能存在一个隐藏的性能瓶颈,因为在阅读代码时,没有明确看到内存被复制(我假设 MyStruct 要复杂得多)。
    如果数字 2 为真,我想知道编译器是否是 总是 能够解决这样的事情。提供的示例非常简单,但我可以想象 my_struct更复杂,在被移到 Rc 之前被不同的函数多次变异。 .

    最佳答案

    Tl;博士 这可能是任何一种情况,但在大多数情况下,您应该以最明显的方式编写代码,让编译器担心它。
    根据抽象机器的语义,即定义 Rust 行为的计算理论模型,始终存在副本。其实至少有两个:my_struct首先在main的栈帧中创建,但随后必须移动到 Rc::new 的堆栈帧中.然后Rc::new必须创建分配并移动 my_struct第二次,从它自己的堆栈帧到新分配的内存*。这些 Action 中的每一个在概念上都是一个副本。
    但是,由于以下三个原因,这种分析对于预测实际代码的性能并不是特别有用:

  • 副本实际上非常便宜。搬家 my_struct从一个地方到另一个地方,从长远来看,实际上可能比用指针引用它便宜得多。复制一大块字节在现代处理器上很容易优化;跟随指向某个任意位置的指针不是。 (还要记住,结构的复杂性是无关紧要的,因为所有的移动都是按字节复制的;例如,移动任何 Vec 只是复制三个 usize 而不考虑内容。)
    如果您还没有测量性能并表明过度复制是一个问题,那么您不能假设它没有证据:您可能会意外地悲观而不是优化您的代码。 先测量。
  • 抽象机器的语义不是你的真实机器的语义。优化编译器的全部意义在于找出将一个转换为另一个的最佳方法。在合理的假设下,这里的代码不太可能在打开优化的情况下产生 2 个副本。但是编译器如何消除一个或两个副本可能取决于代码的其余部分:不仅取决于包含它们的代码段,还取决于如何初始化数据等等。真正的机器性能是复杂的,通常需要一次分析不止几行。同样,这也是优化编译器的全部意义所在:它可以进行更全面的分析,速度比你我快得多。
    即使编译器在“ table 上”留下了一个副本,你也不应该在没有证据的情况下假设删除副本会让事情变得更好,因为它是一个副本。 先测量。
  • 无论如何,在这种情况下,这可能无关紧要。从堆中请求新的分配可能比将一堆字节从一个地方复制到另一个地方更昂贵,因此摆弄 1 个快速副本与没有副本,同时忽略(合理的)大瓶颈可能是浪费时间。在对应用程序或库进行概要分析以查看性能损失最大的地方之前,不要尝试优化事物。 先测量。

  • 也可以看看
    关于意外将大数据放在堆栈上而溢出堆栈的问题(解决方案通常是使用 Vec 而不是数组):
  • How to allocate arrays on the heap in Rust 1.0?
  • Thread '<main>' has overflowed its stack when allocating a large array using Box

  • * Rc ,虽然是标准库的一部分,但是是用普通的 Rust 代码编写的,这就是我在这里分析它的方式。 Rc理论上可能会受到普通代码不可用的有保证的优化,但这恰好与这种情况无关。
    † 至少取决于分配器以及是否必须从操作系统获取新内存,或者是否可以重新使用最近释放的分配。

    关于rust - 将数据移动到 Rc/Arc 是否总是将其从堆栈复制到堆?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68843067/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com