Hình phạt hiệu suất của việc sử dụng clone_from_slice () thay vì copy_from_slice ()?
Trong Rust, có hai phương pháp để cập nhật nội dung của một lát từ một lát khác: clone_from_slice()và copy_from_slice(). Hành vi của hai hàm này không có gì đáng ngạc nhiên - chức năng thứ nhất sao chép và mong đợi kiểu thực thi Clone
, trong khi chức năng thứ hai sao chép và mong kiểu thực hiện Copy
.
Tuy nhiên, tôi ngạc nhiên khi tài liệu cho clone_from_slice
biết điều này: "Nếu được T
cấy ghép Copy
, nó có thể hiệu quả hơn để sử dụng copy_from_slice
." Đáng ngạc nhiên là ở đây cần có sự khác biệt về hiệu suất. Nếu T
thực hiện Copy
, thì .clone()
được yêu cầu tương đương với sao chép các bit; tuy nhiên vì trình biên dịch biết loại T
là gì , nó sẽ có thể tìm ra liệu nó có thể thực hiện sao chép bitwise ngay cả khi tôi sử dụng hay không clone_from_slice
.
Vậy hiệu quả hoạt động kém hiệu quả phát sinh từ đâu?
Trả lời
TL; DR Vui lòng kiểm tra nguồn của clone_from_slice , nó đang truy cập tất cả các phần tử của slice và gọi clone
từng phần tử, trong khi copy_from_slice sao chép trực tiếp tất cả các bit với memcpy
.
Nếu T thực hiện
Copy
, thì.clone()
được yêu cầu tương đương với sao chép bit
Ngay cả khi mọi Copy
loại sẽ triển khai Clone
theo mặc định khi clone
trực tiếp sử dụngcopy
; clone_from_slice
sẽ vẫn đi qua lát cắt và thực hiện sao chép trong khi đi ngang.
Nhưng không có mệnh đề này đúng cho các trường hợp nguyên thủy nhưng không đúng cho các trường hợp như dưới đây :
#[derive(Copy)]
struct X;
impl Clone for X {
fn clone(&self) -> Self {
//do some heavy operation or light(depends on the logic)
X
}
}
Trong khi Clone
có thể được thực hiện bởi bất kỳ Copy
loại logic nào sẽ chỉ sao chép các bit khi nhân bản một đối tượng.
Nếu T thực hiện
Copy
, nó có thể hiệu quả hơn khi sử dụngcopy_from_slice
Điều quan trọng là ở đây, tài liệu nói rằng " nó có thể là " không phải " nó sẽ như vậy ", điều này mang lại những khả năng như
Clone
thực hiện có thể trực tiếp sử dụngCopy
thực hiện. Đối với các loại cơ bản như nguyên thủy, trình tối ưu hóa có thể sử dụng trực tiếpmemcpy
thay vì duyệt ngang, khi đó chúng tôi có thể chấp nhận mệnh đề này là sai vì một cái sẽ không hiệu quả thì cái khác.Clone
thực hiện có thể trực tiếp sử dụngCopy
thực hiện. Đối với các loại phức tạp (vấn đề đi ngang ở trên) làm cho mệnh đề này đúng. (Tôi đã chỉnh sửa ví dụ từ @kmdreko với cấu trúc phức tạp hơn một chút, vui lòng kiểm tra kết quả từ Godbolt )Clone
triển khai là tùy chỉnh và nó là mộtCopy
kiểu, điều này sẽ làm cho mệnh đề này đúng ngay cả khi triển khai tùy chỉnh không tốn kém thìcopy
đối với các lát lớn việc sử dụngmemcpy
có thể có lợi hơn.