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

Mri*_*msh 62 .net collections optimization performance list

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

Ree*_*sey 58

什么会更快,调用Clear()方法或创建一个新的List()?

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

这里最好的选择是:

  1. 描述应用程序,看看这是否真的重要.它可能不会产生任何可察觉的差异,在这种情况下,我会使用最能理解这个对象的方法.

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

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

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

不知道您的具体情况,并测量在探查,也没有办法知道这是您的方案更好.

  • +1来"衡量".正如@NominSim所指出的,Clear可能是昂贵的操作(O(n),因为清除了每个元素,特别是对于大型列表),因此特定场景的分析只是有效选项. (3认同)
  • +1用于解释"清除()"和"新列表<T>"之间的差异,就GC和内存分配而言. (2认同)
  • 我的函数式程序员更喜欢重新初始化变量而不是改变引用,而我的系统程序员更喜欢重用引用(不一定意味着一个更有效)。 (2认同)

ast*_*tef 22

我运行了这个测试:

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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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


Nom*_*Sim 8

这将取决于很多因素,从长远来看,它可能无关紧要(足以计算).

从msdn docs .Clear()是一个O(n)操作.

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

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

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


Joe*_*Joe 6

Clear()将删除所有元素,并保持现有容量,而创建一个新列表将需要从托管堆中至少进行一次分配(如果初始容量较小,则随着项目的添加可能会更多)。

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

  • 如果一次迭代中的项目数量特别多,而后续迭代中的项目数量要少得多,那么使用的Clear成本可能会更高,因为您将在内存中保留一个具有不必要的大容量的列表。

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


hug*_*hug 6

也许我在这里做了一些根本性的错误,但是在使用 C# 开发 ASP.NET 应用程序时,我在使用 Clear() 与 new 时遇到了很大的差异。我正在创建一个带有图表的统计页面,其中包含数据系列。对于每个图表,我都有一个部分来执行此操作:

chart = new ChartistChart() { Title = "My fancy chart" };
series = new List<ChartistMetaValue>();
*some code for getting the statistics*
chart.Series.Add(series);
chartistLineCharts.Add(chart);
Run Code Online (Sandbox Code Playgroud)

然后是另一张图表。

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);
Run Code Online (Sandbox Code Playgroud)

series这对于重新分配来说效果很好new,但是当我这样做时

series.Clear();
Run Code Online (Sandbox Code Playgroud)

相反,我实际上清除了内部条目chart.SerieschartistLineCharts因此统计页面最终仅检索最后一个图表的系列。我假设这里存在一些链接,例如内存指针,这是与最初讨论的问题不同的问题,但这至少是new选择Clear(). 也许有一种方法可以避免它。


Chr*_*ain 5

虽然这可能令人沮丧,但答案确实是它应该无关紧要。两者之间的时间差非常小,可能不会对您的应用程序产生任何影响。做什么会导致代码更清晰、更易于理解,并尽量不要为微优化而编程。


Mic*_*nka 5

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

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

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