【问题标题】:Clone with better performance克隆性能更好
【发布时间】:2011-03-29 17:36:41
【问题描述】:

我想创建深拷贝方法,我找到了 3 种方法来执行它

1-deep copy 将每个属性一一传递

2-使用反射

3-使用序列化

请问哪一个在性能方面是最好的

【问题讨论】:

    标签: c#


    【解决方案1】:

    第一个选项,手动深度复制您的值,将是迄今为止性能最高的。

    反射会引入相当多的开销,因为它(相对)访问数据很慢。

    序列化增加了巨大的成本,因为它将数据序列化为一个临时结构,然后将过程反向设置。这又是,非常慢。

    选项 2 或 3 的唯一优点是它可能更容易实现,并且可以跨多种类型重用。第一个选项必须按类型手写,但速度要快得多(也比选项 3 更有效地使用内存)。

    【讨论】:

    • 反射可以与Emit/IL一起使用,数据访问速度将大大提高。
    • prolly 有人错过了箭头:D
    • @HABJAN:此时,您不再使用反射——而是引入了第四个选项——反射来处理代码生成以直接进行复制。但是,它仍然永远不会像直接复制那样快。
    • @Reed Copsey:我同意它不会像直接复制那么快,但它会比标准反射更快,并且会节省编码时间。
    • @HABJAN:这取决于 - 如果它只有一个类,那么手工完成可能会更快。此外,如果您不经常执行此克隆操作,则运行时编译的开销可能高于反射成本方面的节省。有很多问题会发挥作用,因为该选项的 1 时间成本非常高,但使用成本却更短。
    【解决方案2】:

    我用三种方法的比较加上一个表达式树方法制作了图表。

    对于大量对象,反射比序列化快 5 倍手动代码和表达式树比序列化快 20 倍。因此,性能最好的是手动代码和表达式树。

    使用的克隆代码链接(2.-4.用作扩展方法):

    1. 手动:手动编写,无链接。
    2. Cloning by Serialization
    3. Cloning by Reflection
    4. Cloning by Expression Trees

    【讨论】:

    • 使用您发布的 codeproject.com/Articles/1111658/… 的表达式树克隆代码,使用较新版本的 .Net 框架失败并出现安全异常,操作可能会破坏运行时,它是基本上是由于格式错误的表达式树导致的异常,它用于在运行时生成 Func,请检查您是否有一些解决方案。事实上,我只看到了具有深层层次结构的复杂对象的问题,简单的对象很容易被复制
    【解决方案3】:

    您列出可能的解决方案的顺序是正确的性能顺序。

    当您编写代码以手动克隆每个属性值时,您将获得最佳性能。

    反射将产生与手动克隆类似的结果,但速度稍慢。

    序列化是最糟糕的情况。但实施起来最快。

    Here is a good article that describes other possible solutions.

    所以这里列出了所有可能的克隆方法:

    1. 手动克隆
    2. Clone with MemberwiseClone
    3. Clone with Reflection
    4. Clone with Serialization
    5. Clone with IL
    6. Clone with Extension Methods

    我个人会选择“Clone with IL”,因为它比反射略快,而且您不必手动克隆所有内容。

    【讨论】:

    【解决方案4】:

    最好的性能是在您的代码中创建克隆。所以“1”的方式。

    【讨论】:

      【解决方案5】:

      ICloneable 接口。如果克隆 ICloneable 的东西,使用它的方法是最好的解决方案

      【讨论】:

      • 他在问如何实现它。
      【解决方案6】:

      听起来您已经完成了寻找方法的艰苦工作,所以现在您必须在您的特定情况下对它们进行测试并找出答案。

      在大多数情况下,这实际上取决于您要序列化的什么数据

      【讨论】:

        【解决方案7】:

        反射可用于生成比手动复制更有效的 DynamicMethod(可以通过 skipVisibilityCheck 访问直接打破范围的字段来复制自动属性)。 DynamicMethod 为您提供一个委托,您可以保留在静态只读字段中以克隆您的对象。这是快速简便的方法,但不是最干净的。 序列化很慢而且不适应。

        【讨论】:

          【解决方案8】:

          作为CGbR 的作者,我想邀请您尝试一下您的用例。

          您只需要nuget package 和实现ICloneable 的部分类定义。然后生成的将使用Clone(bool deep) 方法在其旁边创建一个文件。

          public partial class Root : ICloneable
          {
              public Root(int number)
              {
                  _number = number;
              }
              private int _number;
          
              public Partial[] Partials { get; set; }
          
              public IList<ulong> Numbers { get; set; }
          
              public object Clone()
              {
                  return Clone(true);
              }
          
              private Root()
              {
              }
          } 
          
          public partial class Root
          {
              public Root Clone(bool deep)
              {
                  var copy = new Root();
                  // All value types can be simply copied
                  copy._number = _number; 
                  if (deep)
                  {
                      // In a deep clone the references are cloned 
                      var tempPartials = new Partial[Partials.Length];
                      for (var i = 0; i < Partials.Length; i++)
                      {
                          var value = Partials[i];
                          value = value.Clone(true);
                          tempPartials[i] = value;
                      }
                      copy.Partials = tempPartials;
                      var tempNumbers = new List<ulong>(Numbers.Count);
                      for (var i = 0; i < Numbers.Count; i++)
                      {
                          var value = Numbers[i];
                          tempNumbers[i] = value;
                      }
                      copy.Numbers = tempNumbers;
                  }
                  else
                  {
                      // In a shallow clone only references are copied
                      copy.Partials = Partials; 
                      copy.Numbers = Numbers; 
                  }
                  return copy;
              }
          }
          

          性能:在我们工作中需要的克隆基准测试中,将其与DataContractSerializerMemoryStream 进行了比较。生成的代码快 600 倍。

          【讨论】:

            猜你喜欢
            • 2013-10-11
            • 2011-10-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-11-03
            • 2011-12-22
            相关资源
            最近更新 更多