2012-02-23 7 views
8

私はオブジェクトのコレクションを持っています。このコレクションを複製し、さまざまなアプローチのパフォーマンスの意味を理解しようとしています。DeepCloneのパフォーマンス(バイナリシリアル化を使用)とプロパティの手動設定との比較

コレクション内のオブジェクトには、約20個のプロパティすべてstring、ints、float(このオブジェクトの内部にはネストされたオブジェクトはありません)があります。 2つのアプローチがある:

  1. DeepClone()メソッドを作成します。

    public static class ExtensionMethods 
    { 
        public static T DeepClone<T>(this T a) 
        { 
         using (var stream = new MemoryStream()) 
         { 
          var formatter = new BinaryFormatter(); 
          formatter.Serialize(stream, a); 
          stream.Position = 0; 
          return (T)formatter.Deserialize(stream); 
         } 
        } 
    

    }

  2. は手動で "コピー" 私はコレクションをループしていたコードと "新しい" INGのを書きます新しいオブジェクトを作成し、20個のプロパティすべてを手動で設定します。 1は非常に速く、他のものであるべき

    1. :私は人々のフィードバックを取得したいので、この

      public MyObject Copy(MyObject myObj) 
      { 
      var obj = new MyObject(); 
      obj.Prop1 = myObj.Prop1; 
      obj.Prop2 = myObj.Prop2; 
      return obj; 
      

      }

    のようなものは、私は非常に矛盾した結果を取得していますか?私は選択肢2つと思っていただろうが、私のテストではこれをサポートしていないようだから、私が何か間違っているかどうかを判断しようとしている。

  3. これをさらに高速に行う方法はありますか?

+0

浅いコピーを実行したいときにこのDeepClone()というラベルを付けた理由はわかりません。文字列は不変なので、文字列の浅いコピーはディープコピーと同等です。さらに、BinaryFormatterがリフレクションを使用してプロパティ名、セッター、コンストラクタなどを取得するため、手動での設定がはるかに高速になるはずです – Gleno

+0

@Gelno - このメソッドは深くなりますオブジェクトがネストされたオブジェクト(したがって名前)を持つ場合、オブジェクトをクローンします。 – leora

答えて

5

まず、BinaryFormatterルートは、リフレクションを使用してプロパティを取得/設定するため、最初は必ず遅くする必要があります。最も一般的な方法は、コピーコンストラクタと共にIClonableインターフェイスを使用することです。

class A : ICloneable 
{ 
    private readonly int _member; 

    public A(int member) 
    { 
     _member = member; 
    } 

    public A(A a) 
    { 
     _member = a._member; 
    } 

    public object Clone() 
    { 
     return new A(this); 
    } 
} 

もちろん、厳密に言えば、コピーコンストラクタが必要です。これは最速の方法です。あなたのオブジェクトがシンプルな場合は、組み込みのMemberwiseClone関数を使ってみるべきです。

class A : ICloneable 
{ 
    private readonly int _member; 

    public A(int member) 
    { 
     _member = member; 
    } 

    public object Clone() 
    { 
     return MemberwiseClone(); 
    } 
} 

一方で、私はMemberwiseClone()が速いか遅いコピーコンストラクタを使用するよりも深刻だったかどうかを確認するためにsome test codeを書きました。あなたはそれを見つけることができますhere。私は、MemberwiseCloneが、少なくとも小さなクラスでは、CopyConstructorを実行するよりも実際にはるかに遅いことがわかりました。 BinaryFormatterの使用は非常に遅いことに注意してください。

+0

Doesn MemberwiseCloneはリフレクションを使用していますか?それとも、単なるmemcpyなのですか?そしてGCはそれ以上の支援は必要ありませんか? – zmbq

+0

私はパフォーマンスを得るためにいくつかのCLRフックを使うと思います。基本的にはmemcpyといくつかの調整があります。 – Gleno

+0

MemberwiseCloneのヘルプにあるように、BinaryFormatterを使用するのと同じにすることができますか?その関数はDeepCopyという名前が付いているので、私は疑いがあります。名前が間違っていると思います。私のポイントは、深いクローンも参照されたオブジェクトを複製する必要がありますか? – 000

0

これをシリアライズすることは非常に巧妙な考えです。しかし、プロパティを1つずつ設定するのは速くなければならず、ほとんどの場合(オブジェクトが本当に小さい場合を除いて)、処理が少なく、リフレクションを使用しない方が速くなければなりません。

「手作業で」プロパティをコピーするよりも、シリアライゼーションの方が速いケースを再現できますか?

0

シリアル化は、プロパティの割り当てが間違いなく遅くなります。

バイナリシリアル化が推奨されるため、コードは簡単で維持しやすくなります。

代わりにプロパティの割り当ては、クローン中にある可能性があります。すべてのオブジェクトのプロパティを複製したいが、途中でそれらをシリアル化できるようにしたい。要するに、あなたはより多くの流れをコントロールできます。

2

以前の私の役割では、オブジェクトをキャッシュしていて、それらをキャッシュから引き出す前にクローンしたいので、この問題を調査しました。

我々はいくつかの詳細なベンチマークを行なったし、非常に簡単BinaryFormatterアプローチとは対照的に、明らかに手巻きの実装を必要とするが、プロパティの設定は、常に少なくとも一桁速くその後、BinaryFormatterアプローチであることがわかりました。ディープオブジェクトグラフの場合、その差はIIRCにより顕著になりました。タイプは、我々はマーカーインターフェイス、IImutableと意味と思われる(不変だったが、あなたは同じように属性を使用することができれば

  • :最後に

    は、私たちは「クローニング」には3つの方面からのアプローチに定住しました私たちは元のインスタンスを返すことで "複製"します。誰もそれを突然変異させることができないことを知っていたので、同じインスタンスを返却し続けることは安全でした。明らかにこれはクローンの中で最も速いタイプでしたが、明らかにクローンではありません。

  • タイプが独自のIDeepCloneable<T>インターフェイスを実装している場合(これは2番目の例のようになりますが、一般的です)、それを使用します。 [この汎用インタフェースは、非汎用の同等物であるIDeepCloneableから継承します。
  • これは失敗しました。最初の例のBinaryFormatterに戻ります。

あなたは何をしているのかによって、クローンする必要のあるクラスを再設計して、まったくクローンする必要がない場合があることがあります。一度作成したものが本質的に読み込み専用であれば、これは簡単です。たとえそうでなくても、時にはビルダー/不変型のアプローチが有用である(フレーム内のUriUriBuilder参照)。前者は本質的に不変であるが、後者は前者のインスタンスを構築および/または変更するために使用することができる)。

0

すべてのアプローチでは、1)直列化可能なオブジェクトと2)単純な(十分な)オブジェクトが想定されています。ハッシュテーブルを含むことができるオブジェクトがあり、ハッシュテーブルを含むことができ、深度に制限を設けていない場合、再帰的なオブジェクトクロールを行わなくても手を煩わせることになります。

関連する問題