Hukuman kinerja menggunakan clone_from_slice () daripada copy_from_slice ()?

Aug 15 2020

Di Rust, ada dua metode untuk memperbarui konten suatu potongan dari potongan lain: clone_from_slice()dan copy_from_slice(). Perilaku kedua fungsi ini tidak mengejutkan - yang pertama melakukan klon dan mengharapkan tipe untuk diimplementasikan Clone, sementara yang kedua melakukan salinan dan mengharapkan tipe untuk diimplementasikan Copy.

Namun, saya terkejut bahwa dokumentasi untuk clone_from_slicemengatakan ini: "Jika Tdiimplementasikan Copy, dapat lebih efektif untuk digunakan copy_from_slice." Mengejutkan bahwa seharusnya ada perbedaan kinerja di sini. Jika Tmengimplementasikan Copy, maka .clone()diperlukan setara dengan menyalin bit; namun karena kompilator mengetahui jenisnya T, ia harus dapat mengetahui apakah ia dapat melakukan penyalinan bitwise bahkan jika saya menggunakannya clone_from_slice.

Jadi darimana timbulnya inefisiensi kinerja?

Jawaban

4 ÖmerErden Aug 15 2020 at 21:14

TL; DR Silakan periksa sumber clone_from_slice , itu mengunjungi semua elemen slice dan memanggil clonemasing-masing, sementara copy_from_slice langsung menyalin semua bit dengan memcpy.


Jika T mengimplementasikan Copy, maka .clone()diperlukan setara dengan menyalin bit

Bahkan jika setiap Copytipe akan diimplementasikan Clonesecara default di mana clonesecara langsung menggunakancopy ; clone_from_sliceakan tetap melintasi irisan dan melakukan penyalinan saat melintasi.

Tetapi tidak ada proposisi ini yang benar untuk kaum primitif tetapi tidak benar untuk kasus-kasus seperti di bawah ini :

#[derive(Copy)]
struct X;

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

        X
    }
}

Sementara Clonedapat diimplementasikan oleh semua Copyjenis logika hanya akan menyalin bit ketika menduplikasi suatu objek.

Jika T mengimplementasikan Copy, itu bisa lebih berkinerja untuk digunakancopy_from_slice

Yang penting di sini, dokumentasinya mengatakan " bisa jadi " bukan " akan jadi ", ini membawa kemungkinan seperti

  • Cloneimplementasi bisa langsung menggunakan Copyimplementasi. Untuk tipe dasar seperti primitif, pengoptimal dapat langsung menggunakan memcpyalih-alih melintasi, maka kami mungkin menerima proposisi ini sebagai salah karena satu tidak akan berkinerja kemudian yang lain.

  • Cloneimplementasi bisa langsung menggunakan Copyimplementasi. Untuk tipe kompleks (masalah traverse di atas) membuat proposisi ini benar. (Saya telah mengedit contoh dari @kmdreko dengan struktur yang sedikit lebih kompleks, silakan periksa hasil dari godbolt )

  • CloneImplementasinya adalah kustom dan itu adalah Copytipe, yang satu ini akan membuat proposisi ini benar meskipun implementasi kustom tidak mahal maka copyuntuk penggunaan irisan besar memcpymungkin lebih bermanfaat.