Hình phạt hiệu suất của việc sử dụng clone_from_slice () thay vì copy_from_slice ()?

Aug 15 2020

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_slicebiết điều này: "Nếu được Tcấ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 Tthự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 Tlà 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

4 ÖmerErden Aug 15 2020 at 21:14

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 clonetừ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 Copyloại sẽ triển khai Clonetheo mặc định khi clonetrực tiếp sử dụngcopy ; clone_from_slicesẽ 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 Clonecó thể được thực hiện bởi bất kỳ Copyloạ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ư

  • Clonethực hiện có thể trực tiếp sử dụng Copythự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ếp memcpythay 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.

  • Clonethực hiện có thể trực tiếp sử dụng Copythự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 )

  • Clonetriển khai là tùy chỉnh và nó là một Copykiể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ụng memcpycó thể có lợi hơn.