使用 clone_from_slice() 而不是 copy_from_slice() 的性能损失?

Performance penalty of using clone_from_slice() instead of copy_from_slice()?

在 Rust 中,有两种方法可以从另一个切片更新一个切片的内容:clone_from_slice() and copy_from_slice()。这两个函数的行为并不奇怪——第一个执行克隆并期望类型实现 Clone,而第二个执行复制并期望类型实现 Copy.

然而,令我惊讶的是 clone_from_slice 的文档是这样说的:“如果 T 实现了 Copy,那么使用 copy_from_slice 可以提高性能。”令人惊讶的是,这里应该存在性能差异。如果T实现了Copy,则要求.clone()等同于复制位;但是由于编译器知道 T 是什么类型,所以即使我使用 clone_from_slice.

它也应该能够确定它是否可以进行按位复制

那么性能低下的原因是什么?

TL;DR请检查clone_from_slice, it is visiting all the elements of slice and calling clone for each, while copy_from_slice的出处直接复制所有带memcpy的位。

注: Rust 版本 1.52.0clone_from_slice 通过 specialization, if you'd call clone_from_slice with Copy types it will call copy_from_slice internally. (reference)[=42 实现=]


If T implements Copy, then .clone() is required to be equivalent to copying bits

即使每个 Copy 类型默认实现 Clone,其中 clone 直接使用 copyclone_from_slice还是会遍历切片,边遍历边做复制

但是这个命题对原语不正确,但对下面的情况不正确:

#[derive(Copy)]
struct X;

impl Clone for X {
    fn clone(&self) -> Self {
        //do some heavy operation or light(depends on the logic)

        X
    }
}

虽然 Clone 可以通过任何逻辑实现 Copy 类型在复制对象时将简单地复制位。

If T implements Copy, it can be more performant to use copy_from_slice

重要的是在这里,文档说“它可以是”而不是“它会是”,这带来了像这样的可能性

  • Clone实现可以直接使用Copy实现。对于基元这样的基本类型,优化器可能会直接使用 memcpy 而不是遍历,那么我们可能会接受这个命题是错误的,因为一个不会比另一个更高效。

  • Clone实现可以直接使用Copy实现。对于复杂类型(上面的遍历问题)使这个命题正确。 (我编辑了 from @kmdreko with a bit more complex structure, please check the result from godbolt

  • Clone 实现是自定义的,它是一种 Copy 类型,即使自定义实现便宜 copy,这个也会使这个命题正确使用 memcpy 的切片可能更有益。