use*_*095 57 .net c# linq performance
我有人被告知,因为.net linq是如此之慢,我们不应该使用它,并且想知道其他人是否得出了相同的结论,例如:
花了1443ms做了1000000000比较非LINQ.
花了4944ms与LINQ做了1000000000比较.
(慢243%)
非LINQ代码:
for (int i = 0; i < 10000; i++)
{
foreach (MyLinqTestClass1 item in lst1) //100000 items in the list
{
if (item.Name == "9999")
{
isInGroup = true;
break;
}
}
}
Run Code Online (Sandbox Code Playgroud)
花了1443ms做了1000000000比较非LINQ.
LINQ代码:
for (int i = 0; i < 10000; i++)
isInGroup = lst1.Cast<MyLinqTestClass1>().Any(item => item.Name == "9999");
Run Code Online (Sandbox Code Playgroud)
花了4944ms与LINQ做了1000000000比较.
我想它可以优化LINQ代码,但想到的是它很容易得到非常慢的LINQ代码,并且考虑到它不应该被使用.鉴于LINQ很慢,那么PLINQ也会很慢,NHibernate LINQ会很慢,所以不应该使用LINQ语句中的任何类型.
有没有人发现LINQ是如此之慢以至于他们希望从未使用它,或者我是否根据这样的基准做出了过于笼统的结论?
Eri*_*ert 233
Linq应该避免因为它的速度慢吗?
不,如果不够快,应该避免.慢而且不够快并不是完全相同的事情!
慢与您的客户,您的管理层和利益相关者无关.不够快是非常相关的.永远不要测量某物的速度 ; 它告诉你什么都不能用来做出商业决策.衡量客户接受的接近程度.如果可以接受,那就停止花钱让它更快; 它已经足够好了.
性能优化很昂贵.编写代码以便其他人可以阅读和维护代码是昂贵的.这些目标往往是相互对立的,所以为了负责任地花费利益相关者的钱,你必须确保你只花费宝贵的时间和精力对不够快的事情进行性能优化.
您发现了一种人为的,不切实际的基准测试情况,其中LINQ代码比编写代码的其他方式慢.我向您保证,您的客户不会关心您不切实际的基准测试的速度.他们只关心你运送给他们的程序是否太慢.我向你保证,你的管理层对此并不关心(如果他们有能力的话); 他们关心你不必要花多少钱来制作足够快速的东西,并使代码在阅读,理解和维护过程中更加昂贵.
Jon*_*eet 152
你为什么用Cast<T>()
?基本上,你没有给我们足够的代码来真正判断基准.
是的,您可以使用LINQ编写慢速代码.你猜怎么着?您也可以编写慢速非LINQ代码.
LINQ 极大地帮助了处理数据的代码的表现力......只要你花时间去理解LINQ,那么编写表现良好的代码就不那么难了.
如果有人告诉我不要使用LINQ(LINQ尤其是到对象)的感知速度的原因,我会在自己的脸上笑.如果他们想出了一个特定的瓶颈并说:"我们可以通过在这种情况下不使用LINQ来加快速度,这就是证据"那么这是一个非常不同的问题.
Aar*_*ght 84
也许我错过了一些东西,但我很确定你的基准测试是关闭的.
我用以下方法测试:
Any
扩展方法("LINQ")foreach
循环(您的"优化"方法)ICollection.Contains
方法Any
使用优化数据结构的扩展方法(HashSet<T>
)这是测试代码:
class Program
{
static void Main(string[] args)
{
var names = Enumerable.Range(1, 10000).Select(i => i.ToString()).ToList();
var namesHash = new HashSet<string>(names);
string testName = "9999";
for (int i = 0; i < 10; i++)
{
Profiler.ReportRunningTimes(new Dictionary<string, Action>()
{
{ "Enumerable.Any", () => ExecuteContains(names, testName, ContainsAny) },
{ "ICollection.Contains", () => ExecuteContains(names, testName, ContainsCollection) },
{ "Foreach Loop", () => ExecuteContains(names, testName, ContainsLoop) },
{ "HashSet", () => ExecuteContains(namesHash, testName, ContainsCollection) }
},
(s, ts) => Console.WriteLine("{0, 20}: {1}", s, ts), 10000);
Console.WriteLine();
}
Console.ReadLine();
}
static bool ContainsAny(ICollection<string> names, string name)
{
return names.Any(s => s == name);
}
static bool ContainsCollection(ICollection<string> names, string name)
{
return names.Contains(name);
}
static bool ContainsLoop(ICollection<string> names, string name)
{
foreach (var currentName in names)
{
if (currentName == name)
return true;
}
return false;
}
static void ExecuteContains(ICollection<string> names, string name,
Func<ICollection<string>, string, bool> containsFunc)
{
if (containsFunc(names, name))
Trace.WriteLine("Found element in list.");
}
}
Run Code Online (Sandbox Code Playgroud)
不要担心Profiler
班上的内部.它只是Action
在循环中运行并使用a Stopwatch
来计时.它还确保GC.Collect()
在每次测试之前调用以消除尽可能多的噪声.
结果如下:
Enumerable.Any: 00:00:03.4228475
ICollection.Contains: 00:00:01.5884240
Foreach Loop: 00:00:03.0360391
HashSet: 00:00:00.0016518
Enumerable.Any: 00:00:03.4037930
ICollection.Contains: 00:00:01.5918984
Foreach Loop: 00:00:03.0306881
HashSet: 00:00:00.0010133
Enumerable.Any: 00:00:03.4148203
ICollection.Contains: 00:00:01.5855388
Foreach Loop: 00:00:03.0279685
HashSet: 00:00:00.0010481
Enumerable.Any: 00:00:03.4101247
ICollection.Contains: 00:00:01.5842384
Foreach Loop: 00:00:03.0234608
HashSet: 00:00:00.0010258
Enumerable.Any: 00:00:03.4018359
ICollection.Contains: 00:00:01.5902487
Foreach Loop: 00:00:03.0312421
HashSet: 00:00:00.0010222
Run Code Online (Sandbox Code Playgroud)
数据非常一致,并讲述了以下故事:
天真地使用Any
扩展方法比使用foreach
循环的天使慢约9%.
使用ICollection<string>.Contains
具有未优化数据结构(List<string>
)的最合适的方法()比使用循环的天使快约50%foreach
.
HashSet<string>
在性能方面,使用优化的数据结构()完全将任何其他方法从水中吹走.
我不知道你从哪里得到243%.我的猜测是它与所有的铸造有关.如果你正在使用a,ArrayList
那么你不仅使用了未经优化的数据结构,而且还使用了一种基本上过时的数据结构.
我可以预测接下来会发生什么. "是的,我知道你可以更好地优化它,但这只是比较LINQ与非LINQ性能的一个例子."
是的,但是如果你的例子中甚至不能彻底,你怎么可能期望在生产代码中这么彻底呢?
底线是这个:
您构建和设计软件的方式比您使用和何时使用的特定工具更重要.
如果你遇到了性能瓶颈 - 这与LINQ相比没有那么可能发生 - 然后解决它们.Eric对自动化性能测试的建议非常好; 这将帮助您尽早发现问题,以便您可以正确地解决问题- 而不是通过回避一个令您高出80%的工具,但恰好会导致<10%的性能损失,但通过实际调查问题并提出来有一个真正的解决方案,可以将您的性能提高2倍,10倍,或100倍或更多.
创建高性能应用程序并不是要使用正确的库.这是关于分析,做出好的设计选择,以及编写好的代码.
STW*_*STW 16
LINQ是否是现实世界的瓶颈(要么影响应用程序的整体性能还是感知性能)?
您的应用程序是否会在现实世界中的1,000,000,000条记录中执行此操作?如果是这样 - 那么你可能想考虑其他选择 - 如果没有,那就像是说"我们不能购买这款家用轿车,因为它在180+ MPH下驾驶不好".
如果它"只是慢"那么这不是一个很好的理由......通过这种推理你应该用asm/C/C++编写所有东西,而C#应该在桌面上"太慢".
sne*_*rch 12
虽然过早的悲观化(早期)与早期优化一样糟糕,但您不应该在不考虑使用情况的情况下排除基于绝对速度的整个技术.是的,如果你正在做一些非常沉重的数字运算并且这是一个瓶颈,LINQ 可能会有问题 - 简介它.
你可以使用支持LINQ的一个论点是,尽管你可以用手写代码表现得更好,但LINQ版本可能更清晰,更容易维护 - 而且,与复杂的手动并行化相比,PLINQ具有优势.
这种比较的问题在于它在抽象中毫无意义.
如果一个人可以通过他们的Name属性散列MyLinqTestClass1对象来开始,那么可以击败其中任何一个.在那些之间,如果可以按名称对它们进行排序,然后进行二进制搜索.实际上,我们不需要为此存储MyLinqTestClass1对象,我们只需要存储名称.
内存大小有问题吗?也许将名称存储在DAWG结构中,组合足够然后用于此检查?
设置这些数据结构的额外开销是否有意义?这是不可能的.
另一个问题是LINQ概念的另一个问题,即它的名称.MS的营销目的很好,能够说"这里有一堆很酷的新东西可以一起工作",但是当人们在进行那种将它们分开的分析时将各种东西组合在一起时不太好.你需要调用Any
它基本上实现了.NET2.0中常见的可枚举过滤模式(并且.NET1.1并不为人所知,尽管写入更加尴尬意味着它仅在其效率受益的情况下使用某些情况确实很重要),你有lambda表达式,并且你在一个概念中将查询树全部组合在一起.哪个慢?
我敢打赌,这里的答案是lambda而不是使用Any
,但我不打赌大量(例如项目的成功),我会测试并确定.同时,lambda表达式与IQueryable一起使用的方式可以使特别有效的代码在没有使用lambdas的情况下以相同的效率编写是非常困难的.
当LINQ擅长效率时,我们不能提高效率,因为它失败了人工基准吗?我不这么认为.
在有意义的地方使用LINQ.
在瓶颈条件下,然后离开或移到LINQ,尽管它看似合适或不合适作为优化.不要先写下难以理解的代码,因为你只会更难实现真正的优化.
归档时间: |
|
查看次数: |
15496 次 |
最近记录: |