如何解决IEnumerable.Any比带有中断的for循环快吗?
| 我们在打开表单的代码中遇到了一些缓慢,这可能是由于带有break
的for
循环需要花费很长时间来执行。我将其切换为IEnumerable.Any()
,然后看到表格很快打开。我现在试图弄清楚是否单独进行此更改会提高性能,或者它是否可以更有效地访问ProductIDs
属性。这种实现方式应该更快吗?如果可以,为什么?
原始实现:
public bool Containsproduct(int productID) {
bool containsproduct = false;
for (int i = 0; i < this.ProductIDs.Length; i++) {
if (productID == this.ProductIDs[i]) {
containsproduct = true;
break;
}
}
return containsproduct;
}
新实施:
public bool Containsproduct(int productID) {
return this.ProductIDs.Any(t => productID == t);
}
解决方法
第一个实现要快一些(枚举比
for
循环要慢一些)。第二个更具可读性。
更新
奥德的答案可能是正确的,而且在发现它时做得很好。第一个比较慢,因为它涉及数据库往返。否则,它会比我说的快一点。
更新2-证明
这是一个简单的代码,显示为什么第一个速度更快:
public static void Main()
{
int[] values = Enumerable.Range(0,1000000).ToArray();
int dummy = 0;
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < values.Length; i++)
{
dummy *= i;
}
stopwatch.Stop();
Console.WriteLine(\"Loop took {0}\",stopwatch.ElapsedTicks);
dummy = 0;
stopwatch.Reset();
stopwatch.Start();
foreach (var value in values)
{
dummy *= value;
}
stopwatch.Stop();
Console.WriteLine(\"Iteration took {0}\",stopwatch.ElapsedTicks);
Console.Read();
}
输出如下:
循环耗时12198
迭代花费20922
因此循环是迭代/枚举的两倍。
, 称其为有根据的猜测:
this.ProductIDs.Length
这可能就是缓慢之处所在。如果每次迭代都从数据库中检索“ 3”的列表以获取“ 10”,那的确会非常慢。您可以通过对应用程序进行概要分析来确认这一点。
如果不是这种情况(例如,内存中有“ 3”,并且已缓存了“ 10”),则两者的运行时间应该几乎相同。
, 我认为它们或多或少是相同的。我通常参考Jon Skeet的“重新实现LINQ to Objects”博客系列,以了解扩展方法的工作原理。这是Any()
和All()
的帖子
这是该帖子中实施Any()
的核心部分
public static bool Any<TSource>(
this IEnumerable<TSource> source,Func<TSource,bool> predicate)
{
...
foreach (TSource item in source)
{
if (predicate(item))
{
return true;
}
}
return false;
}
, 这篇文章假设ProductIDs
是List<T>
或数组。所以我在谈论Linq-to-objects。
与传统的基于循环的代码相比,Linq通常更慢,但更短/更易读。典型的是2-3倍,具体取决于您的工作。
您可以重构代码以使this.ProductIDs
变成HashSet<T>
吗?或者至少对数组排序,以便可以使用二进制搜索。您的问题是您正在执行线性搜索,如果有很多产品,这会很慢。
, 我认为下面的实现会比相应的linq实现快一点,但是虽然很小
public bool ContainsProduct(int productID) {
var length = this.ProductIDs.Length;
for (int i = 0; i < length; i++) {
if (productID == this.ProductIDs[i]) {
return true;
}
}
return false;
}
, 区别通常是内存使用率和速度。
但是通常,当您知道将要使用数组的所有元素时,应该使用for循环,而在其他情况下,则应尝试使用while或do while。
我认为此解决方案使用最少的资源
int i = this.ProductIDs.Length - 1;
while(i >= 0) {
if(this.ProductIDs[i--] == productId) {
return true;
}
}
return false;
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。