copy_from_slice()の代わりにclone_from_slice()を使用するとパフォーマンスが低下しますか?

Aug 15 2020

Rustでは、別のスライスからスライスのコンテンツを更新する方法が2つあります。clone_from_slice()とcopy_from_slice()。これら2つの関数の動作は驚くべきものではありません。最初の関数はクローンを実行して型が実装されることを期待Cloneし、2番目の関数はコピーを実行して型が実装することを期待しますCopy

ただし、のドキュメントにclone_from_slice次のように記載されていることに驚いています。「をT実装するとCopy、使用するパフォーマンスが向上する可能性がありますcopy_from_slice。」ここでパフォーマンスに違いがあるのは驚くべきことです。をT実装する場合Copy.clone()ビットのコピーと同等である必要があります。ただし、コンパイラTは型が何であるかを知っているので、を使用してもビット単位のコピーを実行できるかどうかを判断できるはずclone_from_sliceです。

では、パフォーマンスの非効率性はどこから発生するのでしょうか。

回答

4 ÖmerErden Aug 15 2020 at 21:14

TL; DR clone_from_sliceのソースを確認してくださいこれは、sliceのすべての要素にアクセスしてcloneそれぞれを呼び出していますが、copy_from_sliceはすべてのビットをmemcpy。で直接コピーします。


Tが実装する場合Copy.clone()ビットのコピーと同等である必要があります

すべてのCopyタイプがCloneデフォルトで実装される場合でもclonecopy ;を直接使用します。clone_from_sliceスライスをトラバースし、トラバース中にコピーを実行します。

しかし、この命題はプリミティブには正しくありませんが、以下のような場合には正しくありません

#[derive(Copy)]
struct X;

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

        X
    }
}

しながら、Clone任意の論理によって実施することができるCopy種類のオブジェクトを複製する際に、単にビットをコピーします。

Tが実装する場合Copy、使用する方がパフォーマンスが高くなる可能性がありますcopy_from_slice

重要なことは、ここにある、ドキュメントが「言うことはできない」「それはなります」、これは次のような可能性をもたらします

  • Clone実装は実装を直接使用できますCopy。プリミティブのような基本的なタイプの場合、オプティマイザーmemcpyはトラバースする代わりに直接使用する可能性があり、一方が他方よりもパフォーマンスが高くないため、この提案を間違っていると受け入れる可能性があります。

  • Clone実装は実装を直接使用できますCopy。複雑なタイプ(上記のトラバースの問題)の場合、この命題は正しくなります。(@kmdrekoの例をもう少し複雑な構造で編集しました。godboltの結果を確認してください)

  • Clone実装はカスタムであり、Copyタイプです。これにより、カスタム実装が安価であっても、この提案が正しくcopyなり、大きなスライスを使用memcpyする方が有益な場合があります。