【问题标题】:Should updating an element in List<T> by index be quicker than using ArrayList index?按索引更新 List<T> 中的元素是否应该比使用 ArrayList 索引更快?
【发布时间】:2010-12-06 00:26:39
【问题描述】:

我正在进行一些关于使用 ArrayLists 和 List 的测试。

速度在我的应用中非常重要。

我已经测试过在每个记录中创建 10000 条记录,通过索引找到一个项目,然后更新该对象,例如:

List[i] = newX;

使用 arraylist 似乎要快得多。对吗?

更新:

使用 List[i] 方法,对于我的 List&lt;T&gt; 方法,我使用 LINQ 来查找索引 eg/

....

int index = base.FindIndex(x=>x.AlpaNumericString = "PopItem");
base[index] = UpdatedItem;

肯定比

ArrayList.IndexOf("PopItem"))
base[index] = UpdatedItem;

【问题讨论】:

  • List 也有一个 IndexOf 方法。效果如何?
  • @Jon:关于您的编辑,您似乎在尝试比较苹果和橙子。 List&lt;T&gt; 中的项目似乎是自定义类型,您正在测试该类型的特定属性以查找索引。 ArrayList 中的项目似乎只是字符串,您正在执行直接相等比较以查找索引。对吗?

标签: c# .net performance .net-3.5 c#-3.0


【解决方案1】:

通用列表 (List&lt;T&gt;) 应该总是比 ArrayList 快。

首先,ArrayList 不是强类型并接受 object 的类型,因此如果您将值类型存储在 ArrayList 中,则每次添加它们时它们将是 boxed and unboxed 或访问。

可以将通用列表定义为仅接受(例如)int,因此在添加/访问列表元素时无需进行装箱或拆箱。

如果您正在处理引用类型,那么使用泛型列表而不是 ArrayList 可能会更好,因为虽然没有装箱/拆箱,但您的泛型列表是类型安全的,并且不会有从 ArrayList 的 object 类型“集合”中检索强类型对象时需要隐式(或显式)强制转换。

在某些极端情况下,ArrayList 的执行速度可能比 Generic List 快,但是,我(个人)还没有遇到过。甚至MSDN documentation 状态:

性能注意事项

在决定是否使用 List)>) 或 ArrayList 类, 两者都有相似的 功能,请记住 List)>) 类表现更好 在大多数情况下,并且是类型安全的。如果一个 引用类型用于类型 T 的 List)>) 类, 两个类的行为是 完全相同的。但是,如果值类型是 用于T型,你需要考虑 实施和装箱问题。

如果值类型用于类型 T, 编译器生成一个 List)>) 的实现 专门针对该值的类 类型。这意味着一个列表元素 List)>) 对象没有 在元素可以被装箱之前 用过,大概500左右的list 创建元素保存的内存 不装箱列表元素更大 比用于生成的内存 类实现。

确定用于的值类型 类型 T 实现 IEquatable)>) 通用接口。如果不, Contains 等方法必须调用 Object..::.Equals(Object) 方法, 将受影响的列表元素装箱。 如果值类型实现 IComparable 接口,您拥有 源代码,也实现 IComparable)>) 泛型 防止 BinarySearch 的接口 和装箱列表中的排序方法 元素。如果您不拥有源 代码,传递一个 IComparer)>) 反对 BinarySearch 和 Sort 方法

此外,我特别喜欢那段的最后一段,它指出:

使用 List)>) 类的特定于类型的实现而不是使用 ArrayList 类或自己编写强类型包装器集合对您有利。 原因是您的实现必须完成 .NET Framework 已经为您完成的工作,并且公共语言运行时可以共享 Microsoft 中间语言代码和元数据,而您的实现则不能。

触摸! :)

【讨论】:

    【解决方案2】:

    根据您最近的编辑,您似乎没有在此处进行 1:1 比较。在 List 中,您有一个类对象,并且您正在寻找基于属性的索引,而在 ArrayList 中,您只存储该属性的值。如果是这样,这是一个有严重缺陷的比较。

    要使其成为 1:1 比较,您只需将值添加到列表中,而不是类中。或者,您可以将类项添加到 ArrayList。前者允许您在两个集合上使用IndexOf。后者需要遍历整个 ArrayList 并比较每个项目,直到找到匹配项(您可以对 List 执行相同操作),或者覆盖 object.Equals,因为 ArrayList 使用它进行比较。

    对于有趣的阅读,我建议看一下 Rico Mariani 的帖子:Performance Quiz #7 -- Generics Improvements and Costs -- Solution。即使在那篇文章中,Rico 也强调需要对不同的场景进行基准测试。尽管普遍的共识是使用泛型列表来提高性能、类型安全和拥有强类型集合,但没有发布关于 ArrayList 的全面声明。

    另一篇相关文章是:Why should I use List and not ArrayList

    【讨论】:

      【解决方案3】:

      ArrayList 似乎更快?根据文档(http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx),使用值类型时列表应该更快,使用引用类型时速度相同。 ArrayList 的值类型较慢,因为它需要在您访问它们时对值进行装箱/拆箱。

      【讨论】:

      • 我的 是一个具有属性的类,例如 CD List 的 CDCollection.... Cd.Artist CD.Genre
      【解决方案4】:

      如果它们是值类型,我希望它们大致相同。 ArrayList 有一个额外的演员表/类型检查,但没什么大不了的。当然,List&lt;T&gt; 应该是首选。如果速度是主要问题(它几乎总是不是,至少不是以这种方式),那么您可能还想分析一个数组(T[]) - 更难(=更昂贵)添加/删除,当然 - 但如果您只是按索引查询/分配,它应该是最快的。对于一些非常本地化性能关键的工作,我不得不求助于数组,但在 99.95% 的情况下,这太过分了,应该避免。

      例如,对于 3 种方法中的 任何一种 (List&lt;T&gt;/ArrayList/T[]),我预计分配成本与 newing up 的成本相比是微不足道的将新实例放入存储中。

      【讨论】:

        【解决方案5】:

        Marc Gravell 在他的回答中谈到了这一点 - 我认为需要强调这一点。

        过早地优化代码通常是浪费时间!

        更好的方法是做一个简单的、精心设计的第一个实现,并使用预期的真实世界数据负载对其进行测试。

        通常,您会发现它“足够快”。 (这有助于从“足够快”的明确定义开始 - 例如“必须能够在 3 秒或更短的时间内在 10,000 个 CD 集合中找到一张 CD”)

        如果不是,请在其上放置一个分析器。几乎总是,瓶颈不会出现在您期望的地方。

        (当我用一个错误选择的字符串连接将整个应用程序推倒在地时,我学到了这一点。)

        【讨论】:

        • 使用 LINQ 方法需要 2 分钟。 IndexOf 花了 2 秒!我想使用 LINQ,但不是那么糟糕
        • 我同意 - 这是一个相当严厉的惩罚!我也喜欢 LINQ,但还没有做足够的事情来理解为什么你的代码会运行这么慢。
        猜你喜欢
        • 1970-01-01
        • 2010-11-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-27
        • 2011-09-08
        • 2012-11-28
        • 1970-01-01
        相关资源
        最近更新 更多