在 Rust 中,有两种方法可以从另一个切片更新一个切片的内容:clone_from_slice()
和 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 的来源, 它正在访问 slice 的所有元素并调用 clone
对于每个,同时 copy_from_slice直接用 memcpy
复制所有位.
注意:对于 Rust 版本 1.52.0,clone_from_slice
通过 specialization 实现, 如果你调用 clone_from_slice
与 Copy
它将调用的类型 copy_from_slice
在内部。 ( reference )
If T implements
Copy
, then.clone()
is required to be equivalent to copying bits
即使每 Copy
类型将实现 Clone
默认情况下 clone
直接使用copy
; clone_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 usecopy_from_slice
重要的是在这里,文档说“它可以”而不是“它会”,这带来了像
这样的可能性Clone
实现可以直接用Copy
执行。对于基元等基本类型,优化器可以直接使用memcpy
而不是遍历,那么我们可能会接受这个命题是错误的,因为一个人不会比另一个人表现更好。Clone
实现可以直接用Copy
执行。对于复杂类型(上面的遍历问题)使这个命题正确。 (我编辑了来自@kmdreko 的 example,结构有点复杂,please check the result from godbolt)Clone
实现是自定义的,它是一个Copy
类型,这个将使这个命题正确,即使自定义实现很便宜copy
对于大切片使用memcpy
可能更有益。
关于使用 clone_from_slice() 而不是 copy_from_slice() 的性能损失?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63426583/