哪个更快:清除集合或实例化新的

时间:2012-06-05 16:21:23

标签: .net performance list optimization collections

我的代码中有一些通用列表,有几十或几百个元素。 有时我需要使用其他对象重新填充此列表,因此问题是:调用Clear()方法或创建new List<T>()会更快?

8 个答案:

答案 0 :(得分:51)

  

什么会更快,调用Clear()方法或创建`新列表()?

这是不可能回答的。这实际上取决于很多因素,包括收藏存在多长时间。

这里最好的选择是:

  1. 对应用程序进行概要分析,看看这是否真的很重要。它可能不会产生任何可察觉的差异,在这种情况下,我会使用对你如何看待这个对象最有意义的方法。

  2. 如果确实重要,请编写两组代码,并测量速度差异(如果有的话)。

  3. 从实际角度来看,调用Clear()实际上不会减少内存(由List<T>本身使用),因为它不会缩小列表的容量,只会消除其中包含的值。创建新的List<T>将导致分配新列表,这将导致更多的分配增长。

    然而,这并不意味着它会变慢 - 在许多情况下,重新分配将更快,因为你不太可能将大型阵列推广到更高的垃圾收集代,转向可以更快地保持GC过程。

    在不了解您的确切场景和测量的情况下,无法知道哪种情况在您的方案中更好。

答案 1 :(得分:18)

我已经运行了这个测试:

private static void Main(string[] args)
{
    int defaultN = 1000;

    Stopwatch sw = new Stopwatch();

    while (true)
    {
        Console.WriteLine("Enter test elements number:");
        int n;
        if (!int.TryParse(Console.ReadLine(), out n)) n = defaultN;
        else defaultN = n;

        Console.WriteLine($"Test with {n} elements");

        List<object> list = Enumerable.Repeat(new object(), n).ToList();
        sw.Start();
        Clear(list);
        sw.Stop();
        Console.WriteLine("Clear: {0} ms", sw.ElapsedTicks / 10000D);

        GC.Collect();
        GC.WaitForPendingFinalizers();

        List<object> list2 = Enumerable.Repeat(new object(), n).ToList();
        sw.Restart();
        Reinitialize(list2);
        sw.Stop();
        Console.WriteLine("Reinitialize: {0} ms", sw.ElapsedTicks / 10000D);

        GC.Collect();
        GC.WaitForPendingFinalizers();

        List<object> list3 = Enumerable.Repeat(new object(), n).ToList();
        sw.Restart();
        ReinitializeAndCollect(list3);
        sw.Stop();
        Console.WriteLine("ReinitializeAndCollect: {0} ms", sw.ElapsedTicks / 10000D);

        Console.WriteLine("===");
    }
}
private static List<object> Clear(List<object> list)
{
    list.Clear();
    return list;
}
private static List<object> Reinitialize(List<object> list) => new List<object>();
private static List<object> ReinitializeAndCollect(List<object> list)
{
    list = new List<object>();

    GC.Collect();
    GC.WaitForPendingFinalizers();

    return list;
}

我的结论基于我的普通核心i3处理器的结果:

如果有数千个元素 - 最好清除列表。它速度快,内存效率高。

如果收集有超过10万个元素 - 重新初始化变得更具吸引力。如果在分析后你认为这里存在瓶颈,请使用它。重新初始化将非常快,但正如第三种方法测试所示,未来的垃圾收集将与清除列表一样慢。

如此简短的回答是:如果您没有分析您的应用程序,请使用Clear。重用对象很好。如果你这样做 - 你已经知道该怎么做了。

答案 2 :(得分:7)

这取决于很多因素,从长远来看,你的程序可能无关紧要(足以计算)。

来自msdn docs .Clear()是一个O(n)操作。

初始化一个新实例将有自己的开销以及(如果你保持集合的长度相同,则为O(n)操作:即n Add()个调用)。

测试这个的唯一方法是在你的程序中设置一些秒表,看看如果你真的认为它是值得的,效果是什么。在所有的可能性;这不值得。

我的想法是,如果你已经创建了一个集合Clear(),那就是为什么首先有一个Clear()方法。

答案 3 :(得分:4)

虽然这可能令人沮丧,但答案实际上是无关紧要的。两者之间的时差将会非常小,以至于它可能对您的应用程序没有任何影响。做什么导致更清晰,更易理解的代码,并尝试不为微优化编程。

答案 4 :(得分:4)

也许我在这里做了一些根本错误的事情,但是在用C#开发ASP.NET应用程序时,我在使用Clear()和new时遇到了很大的不同。 我正在创建一个包含图表的统计页面,这些图表包含数据系列。 对于每个图表,我都有一个部分,我这样做:

chart = new ChartistChart() { Title = "My second fancy chart" };
series = new List<ChartistMetaValue>();
*some code for getting the statistics*
chart.Series.Add(series);
chartistLineCharts.Add(chart);
然后是另一张图表。

series

这可以很好地与new重新分配series.Clear(); ,但是当我这样做时

chart.Series

相反,我实际上清除了chartistLineChartsnew中的条目,因此统计页面最终只检索最后一个图表的系列。我假设这里有一些链接,比如内存指针,这是一个与最初讨论的不同的问题,但这至少是选择Clear()而不是{{1}}的原因。也许有办法避免它。

答案 5 :(得分:3)

Clear()将删除所有元素,并维护现有容量,而创建新列表则需要至少一个来自托管堆的分配(如果初始容量较小,则可能更多地添加项目)。 / p>

  • 如果你有大量的项目,并且每次迭代的项目数量大致相同,那么使用Clear可能会稍快一点。

  • 如果你在一次迭代中拥有特别多的项目,那么在后续迭代中数量要小得多,那么使用Clear可能会更加昂贵,因为你将在内存中保留一个列表不必要的大容量。

当然,在许多(大多数?)场景中,差异可以忽略不计。

答案 6 :(得分:2)

我为自己做了几次测试。结果(速度)是:

  • 对于小型列表 - 例如3个项目,创建新列表的速度更快,但差别不大
  • 平均10个或更多项目最好清除列表。对于价值类型更好(例如3-4次),价值时间更好20%。

但最终,分析应用程序并找到整个应用程序的瓶颈会更好。

答案 7 :(得分:1)

如果您的对象是值类型,我会使用Clear()来减少内存 future 分配。否则两种方法几乎相同。