计算数组的非空元素 - LINQ 性能问题 [重复]

Posted

技术标签:

【中文标题】计算数组的非空元素 - LINQ 性能问题 [重复]【英文标题】:Counting not null elements of array - LINQ performance issue [duplicate] 【发布时间】:2021-09-26 20:39:28 【问题描述】:

我需要一种快速而肮脏的方法来计算数组,但只选择元素是否包含值。经过一番修改后,我想出了这个:

int count = 0;
for (int i = 0; i < array.Length; i++)

    if (array[i] != null)
    count++;

return count;

真的,一个快速的方法来克服这个问题,没有无用的细节 - 然后在搜索 *** 后,我注意到之前有人问过这个问题:Count non null elements in an array of lists

一个非常优雅的答案:使用Enumerable.Count() 强大的计算机之神给了我们这个名为 LINQ 的宝贵工具,我认为我们使用它的次数超出了我们的预期。

array.Count(x => x != null)

看起来很甜美易懂

为了测试它的性能,我创建了一个包含“yes”字符串但只留下 1 的 1 亿元素数组。使用 Stopwatch 类运行测试后,结果相当令人惊讶:

Enumerable.Count:~600 毫秒 脏代码块:~60 ms

在重复执行方面有很大的不同。 这背后的原因可能是什么?我不认为微软的任何工程师都像我一样愚蠢。

【问题讨论】:

这不是关于聪明与否,而是关于一些特殊的东西(你的数组实现)与一些通用的东西(适用于任何IEnumerble&lt;T&gt;)。在大多数情况下,当您真正关心性能时,LINQ 并不是要走的路(它主要是为了易于使用和通用化)。也就是说,还请记住,很难进行良好的性能测试,它们应该以最佳方式进行热身运行,然后进行多次运行,丢弃异常值等(有框架可以为您完成所有这些) 【参考方案1】:

这背后的原因可能是什么?

您的for 循环非常容易让JIT 编译器进行大量优化。这是简单的数组访问、比较和增量。涉及的抽象很少。

LINQ 方法涉及三个抽象:

实现IEnumerable&lt;T&gt;的数组 数组上的每个迭代器都实现IEnumerator&lt;T&gt; 谓词,表示为委托

鉴于所有这些,我对 10 倍的速度差异并不非常感到惊讶。在大多数情况下,它不会阻止我使用 Count... 因为我很少期望 10 倍的速度差异在更广泛的应用程序环境中是显着的。我预计生成/读取 1 亿个数据元素需要比 600 毫秒更长的时间,因此 Count 部分并不需要非常高效。当然,这是一个普遍的期望 - 对于任何对性能很重要的给定应用程序,值得衡量一下哪些部分实际上很重要。

如果您碰巧正在编写一个确实很重要的应用程序,那么不要将 LINQ 用于该部分代码 - 但不要将其扔到其他地方可读性大于性能成本。

【讨论】:

以上是关于计算数组的非空元素 - LINQ 性能问题 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 LINQ 将空值发送到 ASP.NET 中的非空列

计算linq中两个数组中相同元素的数量

给定一个只包含正整数的非空数组,返回该数组中重复次数最多的前N个数字 ,返回的结果按重复次数从多到少降序排列(N不存在取值非法的情况)

python_exercise_给定一个只包含正整数的非空数组,返回该数组中重复次数最多的前N个数字 ,返回的结果按重复次数从多到少降序排列(N不存在取值非法的情况)

List去重

2021-09-30:加一。给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。你可以假设除了整数 0 之外,这个整数