我已经做了很多,我目前正在写的应用程序中使用LINQ查询的,而我一直运行到的是具有与LINQ查询结果转换成用于进一步加工列出情形之一的(我有我的理由想要列表)。
我想有一个更好的了解此列表转换的情况下有效率低下,因为我已经反复使用,现在发生了什么。 所以,给我执行一行行是这样的:
var matches = (from x in list1 join y in list2 on x equals y select x).ToList();
问题:
是否有任何开销这里除了建立一个新的列表,并与在可枚举的元素的引用人口从查询返回?
你会考虑这个效率低下?
有没有办法让LINQ查询直接生成一个列表,以避免在这种情况下转换的需要?
那么,它会创建数据的副本。 这可能是低效的-但要看是怎么回事。 如果你需要一个List<T>
末, List<T>
通常要接近有效率,你会得到。 一个例外是,如果你打算只是做一个转换和源已经是一个名单-然后使用ConvertAll
会更有效率,因为它可以创建大小合适的支持数组开始。
如果你只需要到流的数据-例如,你只是做foreach
就可以了,并采取不影响原始数据源的行动-然后调用ToList
绝对是效率低下的一个潜在来源。 这将迫使整个list1
进行评估-如果这是一个惰性计算序列(如“从一个随机数发生器第1,000,000的测量值”),那么这是不好的。 需要注意的是,你正在做一个连接, list2
将反正只要你尝试拉从序列的第一个值(不管是为了填充列表或不)进行评估。
你可能需要阅读我Edulinq职位上ToList
,看看发生了什么事情-至少在一个可能的实现-在后台运行。
没有任何其他overhed除了已经按您mantioned那些人。
我会说是的,但是这取决于具体的应用场景。 顺便说一句, 一般最好还是避免额外的电话。 (我认为这是明显)。
恐怕不是。 在LINQ query
返回的数据序列 ,这可能是一个无穷远序列可能。 转换为List<T>
你使它FINIT,与也是索引访问,这是不可能的可能性具有在序列或流 。
Suggession:避免在您需要的情况List<T>
如果,顺便说一句,你需要它,里面推的你,你在当前时刻需要更少的数据。
希望这可以帮助。
除了说了些什么,如果你要加入的最初两个列表已经相当大,创造了三分之一(创建两个“相交”)可能会导致内存不足的错误。 如果你只是迭代LINQ语句的结果,你会大大减少内存使用情况。
Enumerable.ToList(source)
本质上只是一个调用new List(source)
。
此构造将测试源是否是一个ICollection<T>
并且如果它是分配适当大小的阵列。 在其他情况下,即,其中所述源是一个LINQ查询大多数情况下,将分配与默认的初始容量(四个项目)的数组,并根据需要通过加倍容量增长它。 每个容量增加一倍的时间,一个新的数组分配和旧的被复制到新的一个。
这可能会引入在案件的一些开销您的列表更是预示了很多的项目(我们可能至少说话千)。 开销能尽快将显著为列表的增长超过85 KB,因为它是那么的大对象堆,这是不板结,可能与内存碎片遭受分配。 请注意,我指的列表中的数组。 如果T
是引用类型,该阵列只包含的引用,而不是实际的对象。 这些对象然后不计为85 KB的限制。
你可以删除一些这方面的开销,如果你能准确地估计您的序列的大小(它是更好地高估一点比它低估了一点点)。 例如,如果你只运行.Select()
上的东西操作实现ICollection<T>
你知道输出列表的大小。
在这种情况下,该扩展方法会减少这方面的开销:
public static List<T> ToList<T>(this IEnumerable<T> source, int initialCapacity)
{
// parameter validation ommited for brevity
var result = new List<T>(initialCapacity);
foreach (T item in source)
{
result.Add(item);
}
return result;
}
在某些情况下,创建列表只是要取代已经在那里的列表,例如:从以前的运行。 在这种情况下,你可以避免不少的内存分配,如果你重复使用旧名单。 如果你没有到旧列表的并发访问,虽然这只会工作,我也不会做,如果新的名单通常会比旧名单显著小。 如果是这样的话,你可以使用这个扩展方法:
public static void CopyToList<T>(this IEnumerable<T> source, List<T> destination)
{
// parameter validation ommited for brevity
destination.Clear();
foreach (T item in source)
{
destination.Add(item);
}
}
这是说,我会考虑.ToList()
是效率低下? 不,如果你有内存,你要重复使用列表中,无论是随机索引到了很多,或者遍历它多次。
现在回到你具体的例子:
var matches = (from x in list1 join y in list2 on x equals y select x).ToList();
这可能是更有效地做到这一点在一些其他的方式,例如:
var matches = list1.Intersect(list2).ToList();
这将产生相同的结果,如果列表1和List2不包含重复的,而且是非常有效的,如果列表2小。
只有这样,才能真正了解,虽然,像往常一样,是使用典型的工作负载来测量。
文章来源: Using ToList() on Enumerable LINQ query results for large data sets - Efficiency Issue?