Hukuman kinerja menggunakan clone_from_slice () daripada copy_from_slice ()?
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_slice
mengatakan ini: "Jika T
diimplementasikan Copy
, dapat lebih efektif untuk digunakan copy_from_slice
." Mengejutkan bahwa seharusnya ada perbedaan kinerja di sini. Jika T
mengimplementasikan 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
TL; DR Silakan periksa sumber clone_from_slice , itu mengunjungi semua elemen slice dan memanggil clone
masing-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 Copy
tipe akan diimplementasikan Clone
secara default di mana clone
secara langsung menggunakancopy
; clone_from_slice
akan 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 Clone
dapat diimplementasikan oleh semua Copy
jenis 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
Clone
implementasi bisa langsung menggunakanCopy
implementasi. Untuk tipe dasar seperti primitif, pengoptimal dapat langsung menggunakanmemcpy
alih-alih melintasi, maka kami mungkin menerima proposisi ini sebagai salah karena satu tidak akan berkinerja kemudian yang lain.Clone
implementasi bisa langsung menggunakanCopy
implementasi. 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 )Clone
Implementasinya adalah kustom dan itu adalahCopy
tipe, yang satu ini akan membuat proposisi ini benar meskipun implementasi kustom tidak mahal makacopy
untuk penggunaan irisan besarmemcpy
mungkin lebih bermanfaat.