我的代码中有一些通用列表,有几十或几百个元素。
有时我需要使用其他对象重新填充此列表,因此问题是:调用Clear()
方法或创建new List<T>()
会更快?
答案 0 :(得分:51)
什么会更快,调用
Clear()
方法或创建`新列表()?
这是不可能回答的。这实际上取决于很多因素,包括收藏存在多长时间。
这里最好的选择是:
对应用程序进行概要分析,看看这是否真的很重要。它可能不会产生任何可察觉的差异,在这种情况下,我会使用对你如何看待这个对象最有意义的方法。
如果确实重要,请编写两组代码,并测量速度差异(如果有的话)。
从实际角度来看,调用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
相反,我实际上清除了chartistLineCharts
和new
中的条目,因此统计页面最终只检索最后一个图表的系列。我假设这里有一些链接,比如内存指针,这是一个与最初讨论的不同的问题,但这至少是选择Clear()
而不是{{1}}的原因。也许有办法避免它。
答案 5 :(得分:3)
Clear()
将删除所有元素,并维护现有容量,而创建新列表则需要至少一个来自托管堆的分配(如果初始容量较小,则可能更多地添加项目)。 / p>
如果你有大量的项目,并且每次迭代的项目数量大致相同,那么使用Clear
可能会稍快一点。
如果你在一次迭代中拥有特别多的项目,那么在后续迭代中数量要小得多,那么使用Clear
可能会更加昂贵,因为你将在内存中保留一个列表不必要的大容量。
当然,在许多(大多数?)场景中,差异可以忽略不计。
答案 6 :(得分:2)
我为自己做了几次测试。结果(速度)是:
但最终,分析应用程序并找到整个应用程序的瓶颈会更好。
答案 7 :(得分:1)
如果您的对象是值类型,我会使用Clear()来减少内存 future 分配。否则两种方法几乎相同。