哪个更好?数组、ArrayList 或 List<T>(在性能和速度方面)

Posted

技术标签:

【中文标题】哪个更好?数组、ArrayList 或 List<T>(在性能和速度方面)【英文标题】:Which is better? array, ArrayList or List<T> (in terms of performance and speed) 【发布时间】:2012-06-04 15:29:49 【问题描述】:

我需要快速处理我的页面。要添加的值的计数将是动态的。

以上哪一项是首选?有正当理由的支持。

编辑:例如:

string str = "a,b,c"; //Count of the number of elements in str is not fixed
string[] arr = str.Split(',');

或者,

ArrayList al = new ArrayList();
al.Add(str.Split(','));

【问题讨论】:

为什么不自己试试呢?此外,这完全取决于您想对 Array、ArrayList 或 List 做什么。我会选择一个最容易使用的,并且只在您真正需要它时才担心性能。 在您的特定情况下尝试每一个,配置文件并查看哪一个最能满足您的需求。它们各自服务于不同的目的。没有适合所有情况的通用“这是最好的”答案。 我喜欢早上 [premature-optimization] 的味道。 List&lt;T&gt;ArrayList 使用数组作为后备存储。它们可以和数组一样快(而且确实如此),但它们不能更快。 类似于***.com/questions/128636/… 【参考方案1】:

List&lt;T&gt; 通常应优先于 ArrayList

值类型更快,因为它避免了装箱。 强类型元素

如果您希望向调用者公开的列表是不可变的,List&lt;T&gt;ArrayList 都支持:

List<T>.AsReadOnly()
ArrayList.ReadOnly(ArrayList list);

您的问题是关于在 ArrayListList&lt;T&gt; 之间进行选择,但您的示例显示了一个数组,但两者都不是。

【讨论】:

那么什么时候选择 ArrayList 比 List 更好?【参考方案2】:

“不可变”集合的数组, List&lt;T&gt; 用于可变集合。

“不可变”集合 - 仅在创建时更改,稍后再阅读。 可变集合 - 一直有很多变化

性能统计数据(Array vs List vs ReadonlyCollection):

       Array                List        ReadOnlyCollection         Penalties      Method
00:00:01.3932446    00:00:01.6677450    00:00:06.2444633    1 vs  1,2  vs  4,5   Generate
00:00:00.1856069    00:00:01.0291365    00:00:02.0674881    1 vs  5,5  vs 11,1   Sum
00:00:00.4350745    00:00:00.9422126    00:00:04.5994937    1 vs  2,2  vs 10,6   BlockCopy
00:00:00.2029309    00:00:00.4272936    00:00:02.2941122    1 vs  2,1  vs 11,3   Sort

源代码:

interface IMethods<T>

  T Generate(int size, Func<int, int> generator);
   int Sum(T items);
   T BlockCopy(T items);
   T Sort(T items);


class ArrayMethods:IMethods<int[]>

  public int[] Generate(int size, Func<int, int> generator)
  
    var items = new int[size];
    for (var i = 0; i < items.Length; ++i)
      items[i] = generator(i);
    return items;
  
  public int Sum(int[] items)
  
    int sum = 0;
    foreach (var item in items)
      sum += item;
    return sum;
  
  public int[] BlockCopy(int[] items)
  
    var res = new int[items.Length / 2];
    Buffer.BlockCopy(items, items.Length / 4 * sizeof(int), res, 0, res.Length * sizeof(int));
    return res;
  
  public int[] Sort(int[] items)
  
    var res = new int[items.Length];
    Buffer.BlockCopy(items, 0, res, 0, items.Length * sizeof(int));
    return res;
  

class ListMethods : IMethods<List<int>>

  public List<int> Generate(int size, Func<int, int> generator)
  
    var items = new List<int>(size);
    for (var i = 0; i < size; ++i)
      items.Add(generator(i));
    return items;
  
  public int Sum(List<int> items)
  
    int sum = 0;
    foreach (var item in items)
      sum += item;
    return sum;
  
  public List<int> BlockCopy(List<int> items)
  
    var count = items.Count / 2;
    var res = new List<int>(count);
    var start = items.Count / 4;
    for (var i = 0; i < count; ++i)
      res.Add(items[start + i]);
    return res;
  
  public List<int> Sort(List<int> items)
  
    var res = new List<int>(items);
    res.Sort();
    return res;
  

class ReadOnlyCollectionMethods:IMethods<ReadOnlyCollection<int>>

  public ReadOnlyCollection<int> Generate(int size, Func<int, int> generator)
  
    return new ReadOnlyCollection<int>(Enumerable.Range(0, size).Select(generator).ToList());
  

  public int Sum(ReadOnlyCollection<int> items)
  
    int sum = 0;
    foreach (var item in items)
      sum += item;
    return sum;
  


  public ReadOnlyCollection<int> BlockCopy(ReadOnlyCollection<int> items)
  
    return new ReadOnlyCollection<int>(items.Skip(items.Count / 4).Take(items.Count / 2).ToArray());
  
  public ReadOnlyCollection<int> Sort(ReadOnlyCollection<int> items)
  
    return new ReadOnlyCollection<int>(items.OrderBy(s => s).ToList());
  


static class Program

  static Tuple<string, TimeSpan>[] CheckPerformance<T>(IMethods<T> methods) where T:class
  
    var stats = new List<Tuple<string, TimeSpan>>();

    T source = null;
    foreach (var info in new[] 
       
        new Name = "Generate", Method = new Func<T, T>(items => methods.Generate(10000000, i => i % 2 == 0 ? -i : i)), 
        new Name = "Sum", Method =  new Func<T, T>(items => Console.WriteLine(methods.Sum(items));return items;), 
        new Name = "BlockCopy", Method = new Func<T, T>(items => methods.BlockCopy(items)), 
        new Name = "Sort", Method = new Func<T, T>(items => methods.BlockCopy(items)), 
        new Name = "Sum", Method =  new Func<T, T>(items => Console.WriteLine(methods.Sum(items));return items;), 
      
     )
    
      int count = 10;
      var stopwatch = new Stopwatch();
      stopwatch.Start();
      T res = null;
      for (var i = 0; i < count; ++i)
        res = info.Method(source);
      stopwatch.Stop();
      source = res;
      stats.Add(new Tuple<string, TimeSpan>(info.Name, stopwatch.Elapsed));
    
    return stats.ToArray();
  

  static void Main()
  
    var arrayStats = CheckPerformance(new ArrayMethods());
    var listStats = CheckPerformance(new ListMethods());
    var rcStats = CheckPerformance(new ReadOnlyCollectionMethods());

    Console.WriteLine("       Array                List        ReadOnlyCollection         Penalties      Method");
    for(var i = 0; i < arrayStats.Length; ++i)
    
      Console.WriteLine("0    1    2    1 vs 3,4:f1  vs 4,4:f1   5", arrayStats[i].Item2, listStats[i].Item2, rcStats[i].Item2, 
        listStats[i].Item2.TotalSeconds / arrayStats[i].Item2.TotalSeconds,
        rcStats[i].Item2.TotalSeconds / arrayStats[i].Item2.TotalSeconds, arrayStats[i].Item1);
    
  

【讨论】:

除了数组不是真正不可变的,IEnumerable&lt;T&gt;IReadOnlyList&lt;T&gt;(.Net 4.5 中的新功能)是。 数组不是不可变的。而是使用ReadOnlyCollection&lt;T&gt; 作为List&lt;T&gt; 周围的不可变包装器 - 通常通过调用List&lt;T&gt;.AsReadOnly() 数组是可变的,当需要不变性时应该避免:blogs.msdn.com/b/ericlippert/archive/2008/09/22/… @DarkGray,事实上,Array 不是不可变的,即创建后可以修改(例如myArray[i] = newValue)。至于性能,您的统计数据毫无意义,因为它们没有显示他们是如何进行测量的。固定大小(即不能添加/删除元素)与不可变(这意味着现有元素也不能替换)不同。 其中一些测试存在缺陷。例如,您的 Array 的 Generate 函数使用了预先知道其大小的事实。但是您不会在 List 生成中做类似的事情(例如,在 List&lt;T&gt; 构造函数中使用容量参数)。【参考方案3】:

List &lt;T&gt; 总是比 arrayList 快。 List &lt;T&gt;'s 不必将添加到其中的值装箱。

ArrayList 仅“接受”对象,这意味着虽然您可以将任何您想要的对象添加到列表中,但必须将其装箱(由 CLR 隐式)然后必须再次取消装箱(显式由您)当您需要这些值时。

编辑:here is a nice link

【讨论】:

装箱差异仅适用于值类型。对于引用类型,两者相等。

以上是关于哪个更好?数组、ArrayList 或 List<T>(在性能和速度方面)的主要内容,如果未能解决你的问题,请参考以下文章

哪个更适合使用,vector 或 arraylist? [复制]

哪个更适合使用,vector 或 arraylist? [复制]

Array 与 ArrayList 的性能 [重复]

Java——ArrayList用法详解

什么时候 ArrayList 比在 C# 中使用数组更有效? [复制]

在性能 Lambda 或简单循环方面哪个更好? [复制]