Pénalité de performance d'utiliser clone_from_slice() au lieu de copy_from_slice() ?
Dans Rust, il existe deux méthodes pour mettre à jour le contenu d'une tranche à partir d'une autre tranche : clone_from_slice()et copy_from_slice(). Le comportement de ces deux fonctions n'est pas surprenant : la première fait un clone et s'attend à ce que le type soit implémenté Clone, tandis que la seconde fait une copie et s'attend à ce que le type soit implémenté Copy.
Cependant, cela me surprend que la documentation de clone_from_sliceindique ceci: "Si Timplements Copy, il peut être plus performant d'utiliser copy_from_slice." Il est surprenant qu'il y ait une différence de performances ici. Si Timplements Copy, alors .clone()doit être équivalent à copier des bits ; cependant, puisque le compilateur sait de quel type Til s'agit, il devrait être capable de déterminer s'il peut faire une copie au niveau du bit même si j'utilise clone_from_slice.
Alors, d'où vient l'inefficacité des performances ?
Réponses
TL;DR Veuillez vérifier la source de clone_from_slice , il visite tous les éléments de slice et appelle clonepour chacun, tandis que copy_from_slice copie directement tous les bits avec memcpy.
Si T implémente
Copy, alors.clone()doit être équivalent à copier des bits
Même si chaque Copytype implémenterait Clonepar défaut où cloneutiliser directement lecopy ; clone_from_slicetraversera toujours la tranche et fera la copie tout en traversant.
Mais non cette proposition est correcte pour les primitives mais pas correcte pour les cas comme ci-dessous :
#[derive(Copy)]
struct X;
impl Clone for X {
fn clone(&self) -> Self {
//do some heavy operation or light(depends on the logic)
X
}
}
Alors que Clonepeut être implémenté par n'importe quel type de logique Copy, il copiera simplement des bits lors de la duplication d'un objet.
Si T implémente
Copy, il peut être plus performant d'utilisercopy_from_slice
La chose importante est ici, la documentation dit " ça peut être " pas " ce sera ", cela apporte des possibilités comme
Clonel'implémentation peut directement utiliser l'Copyimplémentation. Pour les types de base comme les primitives, l'optimiseur peut utiliser directementmemcpyau lieu de traverser, alors nous pourrions accepter cette proposition comme fausse car l'un ne sera pas performant alors l'autre.Clonel'implémentation peut directement utiliser l'Copyimplémentation. Pour les types complexes (le problème de traversée ci-dessus) rend cette proposition correcte. (J'ai modifié l' exemple de @kmdreko avec une structure un peu plus complexe, veuillez vérifier le résultat de godbolt )Clonel'implémentation est personnalisée et c'est unCopytype, celui-ci rendra cette proposition correcte même si l'implémentation personnalisée est peu coûteuse, alorscopypour les grandes tranches, l'utilisationmemcpypourrait être plus bénéfique.