【问题标题】:Performance testing ArrayList in C#C# 中的 ArrayList 性能测试
【发布时间】:2011-10-23 06:58:56
【问题描述】:

我想对 ArrayList(System.Collections - C#) 在开头插入项目的速度进行性能测试。

我打开了一个文件来读取数据行,设置了一个秒表,还创建了一个 ArrayList 来添加项目(如下):

Stopwatch watchTime = new Stopwatch();
Double totalTime = 0; 
using (StreamReader readText = new StreamReader("data.txt"))
{
    String line;
    Int32 counter = 0; 
    while ((line = readText.ReadLine()) != null)
    {
    }
}

我使用计数器来跟踪我要进入 ArrayList 的项目数。

在 while 循环中,我有以下内容:

watchTime.Start();
theList.Insert(0, line);
watchTime.Stop();
Double time = watchTime.Elapsed.TotalMilliseconds;
totalTime = totalTime + time; 
Console.WriteLine(time);
watchTime.Reset();
++counter; 

这是检查将项目插入到 ArrayList 开头的速度的正确方法吗?

我制作了另一个程序,它做同样的事情 - 但是使用字典。令我惊讶的是,这个 ArrayList 插入项目所需的时间比 Dictionary 所需的时间长得多。为什么会这样?

【问题讨论】:

  • 您可以启动像 ANTS Profiler 这样的性能分析器并查看性能进展情况。
  • 为什么要测量ArrayList。自 .NET 2.0 以来,它已被弃用。
  • @Henk 对不起,你能解释一下为什么会这样吗?秒表仅围绕插入 - 没有其他任何东西。

标签: c# performance insert arraylist performance-testing


【解决方案1】:

好吧,我建议:

  • 不要使用文件来获取输入。为什么要在系统中引入 IO?
  • 无需重复停止和启动秒表,只需在ArrayList 中插入大量行,无需执行任何其他操作。一口气计时那个大循环。

至于为什么Dictionary<,> 更便宜 - 你没有显示任何代码,但基本上你的插入代码必须在每次插入时复制ArrayList 的全部内容。 ArrayList 维护一个数组来保存列表的内容。通常数组比列表大 - 当你在最后添加一个元素时,如果可以将新值分配到数组的正确位。如果将它插入到别处,它必须复制数组的元素以为新元素“腾出空间”。

您会发现在最后添加它要快得多。 Dictionary<,> 使用完全不同的数据结构;它必须在某些时候调整大小,但通常会有非常不同的特征。

(我建议您使用List<T> 而不是ArrayList 开头,如果您想要一个可以在开头重复插入的集合,请考虑使用LinkedList<T> - 或者可能是队列或堆栈,具体取决于关于你以后想用它做什么。)

【讨论】:

  • 谢谢,阅读这篇文章实际上有助于解释为什么我看到 ArrayList 花了这么多时间才在开头插入一些东西。我实际上想对 ArrayList 与 Dictionary 进行性能测试,只是为了了解它是如何工作的,以及为什么在不同的地方插入时可能会比另一个慢...感谢您的回复 - 非常有帮助。
  • @BlueButtons:值得理解的是,虽然列表是有序的,但字典不是 - 您并没有真正插入字典中的“位置”,您只需将键映射到值.
  • @Jon 这是否意味着您拥有的键类型(即 int 或 string)也会影响使用字典时插入发生的速率?我猜会的。
  • @Jon btw,很酷的网站。我将浏览您的新旧网站。看来你有很多很好的知识可以提供。
  • @BlueButtons:在某种程度上,它也必须采用哈希值。但是您很少想在列表或字典之间做出决定——它们有不同的用途。如果您想要有序列表,请使用列表。如果您想要任意映射,请使用字典。
【解决方案2】:

太复杂了。在末尾附加的列表中“正常”读取文件,然后将第一个列表添加到第二个列表中进行基准测试。否则,您会尝试对太多的小动作进行基准测试,并且会遇到精度问题。

一些代码

ArrayList tempList = new ArrayList();

using (StreamReader readText = new StreamReader("data.txt"))
{
    String line;
    Int32 counter = 0; 
    while ((line = readText.ReadLine()) != null)
    {
        tempList.Add(line);
    }
}

ArrayList theList = new ArrayList();

Stopwatch watchTime = Stopwatch.StartNew();

foreach (string line in tempList)
{
    theList.Insert(0, line);
}

watchTime.Stop();

我将添加Stopwatch,您可以使用StartStop,然后再次添加Start,它将继续保持时间。要重置它,还有另一种方法,Restart

正如其他人可能建议的那样:

  • 使用List<string>而不是ArrayList(速度相同,但List<string>是类型安全的)
  • 一般来说,如果你只需要在列表的头部插入元素,在尾部插入它们(更快)并“反转”索引(所以索引0是索引Count - 1,1是@ 987654332@ 等)。列表不是为“中间”或“顶部”插入而“制作”的。它们是为“添加最后”而制作的。

【讨论】:

  • 如果唯一的目的是对ArrayList.Insert进行基准测试,为什么还要费心阅读这些行呢?只需多次插入相同的字符串引用。
  • 好的,谢谢。我会试试这个,看看我得到什么类型的结果。感谢您的回复,非常感谢。
  • @JonSkeet 他读了文件才知道有多少字符串 :-) 我以为他必须读一个文件,而不是他想看看 ArrayList 的 O(n) 慢了多少为了它。
  • @JonSkeet 最后你是对的,如果他只想找到插入对 ArrayList 头部的引用的速度并测量这个插入的衰减速度。
猜你喜欢
  • 2018-12-09
  • 1970-01-01
  • 1970-01-01
  • 2010-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多