【问题标题】:Is there a faster way to clone a list of items?有没有更快的方法来克隆项目列表?
【发布时间】:2015-07-02 03:55:37
【问题描述】:

有没有比下面显示的更快的克隆项目的方法?

private List<T> CloneItems(List<T> itemsToClone) {
    lock (dataLocker) {
        Stopwatch sw = Stopwatch.StartNew();

        int numItems = itemsToClone.Count;
        List<T> itemsToBeReturned = new List<T>(numItems);

        for (int i = 0; i < numItems; i++) {
            itemsToBeReturned.Add((T)itemsToClone[i].Clone());
        }

        Debug.WriteLine("CloneItems(ms): " + sw.Elapsed.TotalMilliseconds.ToString("F3"));
        return itemsToBeReturned;
    }
}

编辑:我需要一个深层副本,目前正在将它与以下对象一起使用:

public class TimestampedDouble {
    public long Timestamp { get; set; }
    public double Voltage { get; set; }
    public double Current { get; set; }
    ...
    public override object Clone() {
        return MemberwiseClone();
    }
}

【问题讨论】:

  • 浅克隆还是深克隆?
  • 为什么投反对票?我做错了什么?
  • @RonBeyer 如果这三个属性是唯一的,那么在 this 特定情况下,这将是一个深拷贝,因为这些属性都是值类型。
  • 您要复制这些TimestampedDouble 中的多少?你试过this answer之类的吗?
  • @Cameron 我每 20 毫秒复制数百个 TimestampedDoubles。我查看了您的链接答案并尝试了这个变体(据说比序列化方法快 3 倍),它比我在原始帖子中的方法慢约 20 倍:raw.github.com/Burtsev-Alexey/net-object-deep-copy/master/…

标签: c# performance list clone


【解决方案1】:

就像其他人提到的那样,您需要找到实际的瓶颈。就其功能而言,您上面的代码相当紧凑。很可能,它是克隆而不是你的循环。但是,事实证明,Microsoft 已经在 ConvertAll 方法中为您完成了该循环,您可以像这样重新实现上面的代码:

var finallist = itemsToClone.ConvertAll<T>(o => (T)o.Clone());

但是,我猜这不会是一场胜利,因为如果 被要求实施 ConvertAll,我会做一些接近你的循环的事情。事实上,that's pretty much what MS did

这将直接指向您的 Clone 方法作为罪魁祸首。

【讨论】:

    【解决方案2】:

    您可以使用这样的扩展方法:

    static class Extensions
    {
        public static IList<T> Clone<T>(this IList<T> listToClone) where T: ICloneable
        {
            return listToClone.Select(item => (T)item.Clone()).ToList();
        }
    }
    

    【讨论】:

    • 鉴于此操作中的大部分时间可能会花费在Clone 方法中,这不太可能对整个操作所花费的时间量产生显着影响.但是,由于我可能是错的,你可以包括为什么你认为这更快的原因。
    • 仅供参考,Select() 给出了一个 IEnumerable。 ToList() 不会先验地知道需要分配多少项目,因此它必须增加列表(取决于项目的数量)。
    • @Aram 我尝试了这个变体(不是作为扩展方法),它比我在问题中显示的方法慢了大约 2 倍: List listCloned = itemsToClone.Select(i => (T) i.Clone()).ToList();
    【解决方案3】:

    对我来说看起来很可靠。其他建议将是更少的代码,但不是更快。尤其是未预分配数组大小时的建议。

    我的最佳想法是让TimestampedDoublestruct 可以更快地摆脱分配和垃圾回收。

    但是,如果您可以将其余代码重组为不需要整个列表,而改为使用管道,那将是最好的选择。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-02-27
      • 2011-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多