为了账号安全,请及时绑定邮箱和手机立即绑定

调用ToList()会对性能产生影响吗?

调用ToList()会对性能产生影响吗?

C#
慕村9548890 2019-11-11 10:25:49
使用时ToList(),是否需要考虑对性能的影响?我正在编写一个查询来从目录(即查询)中检索文件:string[] imageArray = Directory.GetFiles(directory);但是,由于我想与之合作List<>,所以我决定投入...List<string> imageList = Directory.GetFiles(directory).ToList();因此,在决定进行这种转换时是否应该考虑某种性能影响?或者仅在处理大量文件时才考虑?这是微不足道的转换吗?
查看完整描述

3 回答

?
慕的地8271018

TA贡献1796条经验 获得超4个赞

IEnumerable.ToList()

是的,IEnumerable<T>.ToList()确实会对性能产生影响,尽管可能只需要关注性能关键的操作,但它是O(n)操作。


该ToList()操作将使用List(IEnumerable<T> collection)构造函数。这个构造函数必须复制数组(通常是IEnumerable<T>),否则将来对原始数组的修改T[]也将在源上更改,这通常是不希望的。


我想重申的是,这只会对庞大的列表有所作为,复制内存块是一项非常快速的操作。


方便的提示,AsvsTo

您会在LINQ中注意到有几种以As(如AsEnumerable())和To(如ToList())开头的方法。开头的方法To需要进行上述转换(即可能会影响性能),而开头的方法As则不需要,只需要进行一些强制转换或简单操作即可。


有关的其他详细信息 List<T>

List<T>如果您有兴趣,这里有一些工作原理的详细信息:)


A List<T>还使用一种称为动态数组的结构,该结构需要按需调整大小,此调整大小事件将旧数组的内容复制到新数组。因此,它从很小的地方开始,并在需要时增加尺寸。


这是的Capacity和Count属性之间的区别List<T>。Capacity指的是幕后数组的大小,Count是其中的项目数List<T>始终为<= Capacity。因此,当将一项添加到列表中时,将其增加到之后Capacity,的大小将List<T>增加一倍,并复制数组。


查看完整回答
反对 回复 2019-11-11
?
拉莫斯之舞

TA贡献1820条经验 获得超10个赞

调用toList()会对性能产生影响吗?


当然是。从理论上讲i++,它甚至会对性能产生影响,可能会使程序变慢几格。


怎么.ToList办?


调用时.ToList,代码将调用Enumerable.ToList()作为扩展方法的return new List<TSource>(source)。在相应的构造函数中,在最坏的情况下,它将遍历item容器并将它们一个接一个地添加到新容器中。因此,它的行为对性能几乎没有影响。成为应用程序的性能瓶颈是不可能的。


问题中的代码有什么问题


Directory.GetFiles遍历该文件夹并将所有文件的名称立即返回到内存中,这有可能会导致string []占用大量内存,从而减慢一切。


那应该怎么办


这取决于。如果您(以及您的业务逻辑)保证该文件夹中的文件数量始终很小,那么该代码是可以接受的。但是仍然建议使用懒惰版本:Directory.EnumerateFiles在C#4中。这更像是查询,不会立即执行,您可以在其上添加更多查询,例如:


Directory.EnumerateFiles(myPath).Any(s => s.Contains("myfile"))

一旦找到名称包含“ myfile”的文件,它将立即停止搜索路径。这显然具有更好的性能.GetFiles。


查看完整回答
反对 回复 2019-11-11
?
www说

TA贡献1775条经验 获得超8个赞

调用toList()会对性能产生影响吗?

就在这里。使用扩展方法Enumerable.ToList()将从源集合构造一个新List<T>对象,IEnumerable<T>这当然会对性能产生影响。

但是,了解List<T>可能会帮助您确定性能影响是否重大。

List<T>使用数组(T[])存储列表的元素。数组一旦分配就无法扩展,因此List<T>将使用超大数组来存储列表中的元素。当List<T>增长超出基础数组的大小时,必须分配新数组,并且必须在列表可以增长之前将旧数组的内容复制到新的较大数组。

List<T>从中构造新对象时,IEnumerable<T>有两种情况:

  1. 源集合的实现ICollection<T>:然后ICollection<T>.Count用于获取源集合的确切大小,并在使用ICollection<T>.CopyTo()。将源集合的所有元素复制到支持数组之前分配一个匹配的支持数组。此操作非常有效,可能会映射到某些CPU指令以复制内存块。但是,就性能而言,新阵列需要内存,复制所有元素需要CPU周期。

  2. 否则源集合的大小是未知的,并且使用的枚举器IEnumerable<T>将每个源元素一次添加到新元素中List<T>。最初,支持数组为空,并创建了大小为4的数组。然后,当此数组太小时,其大小将增加一倍,因此后备数组将像4、8、16、32等那样增长。每当后备数组增长时,都必须重新分配它,并且必须复制到目前为止存储的所有元素。与可以立即创建正确大小的数组的第一种情况相比,此操作的成本要高得多。

    另外,如果您的源集合包含33个元素,则该列表最终将使用64个元素的数组浪费一些内存。

在您的情况下,源集合是一个实现的数组,ICollection<T>因此,除非源数组很大,否则您不必担心性能影响。调用ToList()将只复制源数组并将其包装在一个List<T>对象中。即使是第二种情况的性能,也不必为小收藏而担心。


查看完整回答
反对 回复 2019-11-11
  • 3 回答
  • 0 关注
  • 951 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信