是否应该避免使用 LINQ,因为它很慢? [关闭]
Posted
技术标签:
【中文标题】是否应该避免使用 LINQ,因为它很慢? [关闭]【英文标题】:Should LINQ be avoided because it's slow? [closed] 【发布时间】:2011-04-15 18:15:52 【问题描述】:有人告诉我,由于 .net linq 太慢了,我们不应该使用它,并且想知道其他人也得出了相同的结论,例如:
1000000000 次非 LINQ 比较耗时 1443 毫秒。 用 4944 毫秒完成 1000000000 次与 LINQ 的比较。 (慢 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;
用了 1443 毫秒来进行 1000000000 次非 LINQ 比较。
LINQ 代码:
for (int i = 0; i < 10000; i++)
isInGroup = lst1.Cast<MyLinqTestClass1>().Any(item => item.Name == "9999");
与 LINQ 进行 1000000000 次比较耗时 4944 毫秒。
我想它可以优化 LINQ 代码,但我认为它很容易获得非常慢的 LINQ 代码,并且不应该使用它。鉴于 LINQ 很慢,那么 PLINQ 很慢,NHibernate LINQ 也很慢,因此不应使用任何类型的 LINQ 语句。
有没有其他人发现 LINQ 太慢以至于他们希望自己从未使用过它,或者我是否基于这样的基准做出了过于笼统的结论?
【问题讨论】:
尝试重组你的对象,这样你就不需要cast
...
我不会避免使用代码,因为它每秒只执行 2.5 亿个周期而不是大约 7.5 亿个周期,除非这种吞吐量是一个实际的业务案例。此外,数据很可能来自比这段代码慢很多的东西(数据库、磁盘等)。选择看起来最方便的东西,并在重要的地方进行优化。
也许您应该更担心的是您担心需要多花 3.5 纳秒...
根据这种推理,您应该放弃 .NET,因为它很慢。转到像 C++ 这样的本机编译语言。哦,但是 C++ 的库并未针对您的特定情况进行优化,因此请使用没有任何库的 C。当然,编译器会做出假设(尽管编译器通常比非经验丰富的开发人员更聪明),所以请阅读汇编并改用它。举个例子,新的语言/功能使编程更容易和更易于维护,但通常不会更快。您更喜欢易于阅读的程序还是快 3.5 纳秒的程序?这取决于您的业务案例。
根据您在此线程中的 cmets,您似乎已经准备好不使用 LINQ,尽管人们已经说过。不确定您的目的是什么——希望确认您是对的,而不是寻找正确的?
【参考方案1】:
是否应该避免 Linq,因为它很慢?
没有。如果它不够快,应该避免它。 慢和不够快根本不是一回事!
慢与您的客户、您的管理层和您的利益相关者无关。 不够快是非常相关的。永远不要衡量某样东西的速度有多快;这不会告诉您任何可以用来作为业务决策基础的信息。衡量客户接受的程度。如果可以接受,那就停止花钱让它更快;已经够好了。
性能优化是昂贵的。编写代码以供他人阅读和维护是昂贵的。这些目标经常相互对立,因此为了负责任地花费利益相关者的钱,您必须确保您只将宝贵的时间和精力花费在不够快的事情上进行性能优化时间>。
您发现了一种人为的、不切实际的基准测试情况,即 LINQ 代码比其他编写代码的方式慢。我向您保证,您的客户一点也不关心您不切实际的基准测试的速度。他们只关心您发送给他们的程序是否对他们来说太慢。我向你保证,你的管理层根本不关心这个(如果他们有能力的话);他们关心的是你花了多少不必要的钱来让足够快的东西变得更快,并让代码在这个过程中阅读、理解和维护的成本更高。
【讨论】:
@user455095:所以你的意思是你知道的魔鬼比你不知道的魔鬼要好。这很好,如果您喜欢根据古语做出商业决策。我认为,根据来自经验测量的知情意见做出商业决策通常是一个更好的主意。通过进行经验测量,您将朝着正确的方向前进,这很好。但是您正在将该测量值与错误的事物进行比较。您应该衡量的是客户满意度和股东成本,而不是每次比较的微秒。 @user:不如“消除任何可能导致性能问题的东西”,而是从正确且易于维护的代码开始,然后消除特定性能问题他们来了(如果您的软件架构良好且设计良好,这应该很容易)?我不想这么直率,但你基本上是在向全世界宣布你不知道如何做你的工作。您的“问题”的一部分似乎是代码是如此“庞大” - 好吧,猜猜看,如果您有效地使用 LINQ,它不会那么庞大。 @user,我向您保证,会有一些示例表明 LINQ 的执行速度比您自己编写的代码要快。不是因为您无法编写比 LINQ 更快的代码,而是您没有时间这样做。您将所有时间都花在尝试满足规范、集成经常相互矛盾的业务规则、查找和消除错误等。同时,Microsoft 有一个团队优化Join
操作。使用 LINQ,您将编写更具表现力的代码,并且编写速度更快。它也会表现良好。
@user455095:听起来你对未来的表现有些焦虑。减轻这种焦虑的方法是制定夜间自动化性能测试策略,根据真实客户指标衡量真实产品的性能。这样,您每天都可以跟踪绩效数字的趋势。如果您发现糟糕的性能突然飙升,那么您可以检查当天的所有更改日志,并找出导致性能不佳的更改。在您不知情的情况下,修复性能问题的时间越长,成本就会越高!
@user455095:那为什么还要担心呢?今天尝试使用 LINQ,明天您就会知道它是否会导致无法接受的高性能下降。你说使用LINQ的不确定性太高了;好吧,除非您花一些时间使用它并了解什么对您有用,什么对您无效,否则您不会变得更加确定。如果您的问题真的是“是否应该避免使用 LINQ,因为我的团队不了解如何有效地使用它?”那么这与您提出的问题不同。我对这个问题的回答是“不;相反,学习如何有效地使用它!”【参考方案2】:
你为什么使用Cast<T>()
?基本上,你没有给我们足够的代码来真正判断基准。
是的,您可以使用 LINQ 编写慢代码。你猜怎么了?您也可以编写慢速非 LINQ 代码。
LINQ 非常有助于处理数据的代码的表现力......而且编写性能良好的代码并不难,只要您花时间了解 LINQ。 p>
如果有人出于感知速度的原因告诉我不要使用LINQ(尤其是LINQ to Objects),我会当着他们的面笑。如果他们提出一个特定的瓶颈并说,“我们可以通过在这种情况下不使用 LINQ 来加快速度,这是证据”,那么情况就完全不同了。
【讨论】:
是的,我回答说去掉石膏会有帮助,但被告知它没有那么慢,但仍然很慢。我们的应用程序需要很快,所以我想这个想法是应该避免任何可能很慢的事情,但我不确定这是否是一个有效的假设 @user455095:不,这绝对不是一个有效的假设。 “慢”远不是一个精确的术语——我非常怀疑这是一个现实的基准。 我遇到的唯一一次出于性能原因删除 LINQ 的案例是在游戏中实现 AI 的例程。这种特殊的方法在深层内部循环中非常频繁地执行。我发现的主要影响实际上并不是 LINQ,而是直接通过数组索引与通过枚举器索引之间的区别(我的第一次改进尝试是直接使用 foreach,这比切换到经典 for 循环的好处少。 ) 我之所以进行此更改,是因为分析发现代码在这里花费了 40% 的时间。 “如果有人告诉我不要使用 LINQ(尤其是 LINQ to Objects)以提高速度,我会当面嘲笑他们。”出于同样的原因,我实际上已经笑了好几张脸。另外,当他们说“我看不到价值”时。 “我们的应用程序需要很快,所以我想这个想法是应该避免任何可能很慢的事情” - 这是我听过的最愚蠢的事情。字符串可能很慢。数组可能很慢。虚拟方法可能很慢,接口可能很慢。任何事情都可能很慢,如果你用错了,但这并不意味着你应该在代码中避免所有那些everywhere的东西。【参考方案3】:也许我遗漏了一些东西,但我很确定你的基准测试不合格。
我用以下方法测试:
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.");
不用担心Profiler
类的内部结构。它只是在循环中运行Action
并使用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
数据非常一致,讲述了以下故事:
天真地使用 Any
扩展方法比天真地使用 foreach
循环慢约 9%。
对未优化的数据结构 (List<string>
) 使用最合适的方法 (ICollection<string>.Contains
) 比单纯使用 foreach
循环要快 50%快。
使用优化的数据结构 (HashSet<string>
) 在性能方面完全颠覆了任何其他方法。
我不知道你从哪里得到 243%。我的猜测是这与所有的演员阵容有关。如果您使用的是ArrayList
,那么您不仅使用了未优化的数据结构,而且使用了很大程度上过时的数据结构。
我可以预测接下来会发生什么。 “是的,我知道你可以更好地优化它,但这只是比较 LINQ 与非 LINQ 性能的一个示例。”
是的,但是如果您在示例中甚至不能彻底,那么您怎么可能期望在生产代码中如此彻底?
底线是这样的:
您如何架构和设计您的软件比您使用什么特定工具以及何时使用更为重要。
如果您遇到性能瓶颈(使用 LINQ 与不使用 LINQ 的可能性一样),请解决它们。 Eric 对自动化性能测试的建议非常好。这将帮助您及早发现问题,以便您可以正确解决它们 - 不是回避一个让您的工作效率提高 80% 但碰巧会导致性能下降 调查问题并提出真正的解决方案,可以将您的绩效提高 2 倍、10 倍、100 倍或更多。
创建高性能应用程序与使用正确的库无关。这是关于分析、做出好的设计选择和编写好的代码。
【讨论】:
我忘了说,这是用TRACE
标志关闭编译的,所以这个测试不会产生任何开销。
将 enumerable 转换为 hashset 的成本如何?【参考方案4】:
LINQ 是否是现实世界的瓶颈(影响应用程序的整体或感知性能)?
您的应用程序会在现实世界中对超过 1,000,000,000 条记录执行此操作吗?如果是这样 - 那么您可能需要考虑替代方案 - 如果不是,那么就像是在说“我们不能购买这款家用轿车,因为它在 180 英里/小时以上的速度下行驶不佳”。
如果它“只是慢”,那么这不是一个很好的理由......根据这个理由,您应该用 asm/C/C++ 编写所有内容,而 C# 应该因为“太慢”而被排除在外。
【讨论】:
应用程序中没有一个地方存在性能问题,但它更像是一个想法,如果出于某种原因,代码像示例一样被执行了十亿次,并且鉴于此,它不应该使用。 虚无缥缈是怎么回事?你是知道你的代码在做什么以及它是如何做的人。如果 LINQ 执行速度很慢,则不要使用 LINQ。如果没有性能问题,那也没关系,不是吗? @user455095:代码是否存在性能问题?如果不是,那么其中的所有内容都运行得足够快,并且不值得仅仅因为它很慢而对其进行更改。如果代码确实存在性能问题,请分析以查看 LINQ 调用是否具有显着影响。如果是,请双向测试。如果 LINQ 更易读、写得更快、更容易正确、更容易维护或类似的东西,那么它可能值得一些性能打击。 我的回答是 3426195426 与非 LINQ 代码进行比较也需要 4944 毫秒,因此在此基础上您也不应该使用非 LINQ 代码...... @user455095:很抱歉,您关于未来可能会导致一些微不足道的性能问题的未来情景的论点站不住脚。听这些人的;他们知道他们在说什么。 Eric Lippert 在构建您的 C# 编译器的团队中工作,以防您不知道。 Jon Skeet 为 Google 工作。这两位先生和这里的其他人都想告诉你一些事情。 L I S T E N.【参考方案5】:虽然过早悲观(恕我直言)与过早优化一样糟糕,但您不应该在不考虑使用上下文的情况下排除基于绝对速度的整个技术。是的,如果您正在执行一些非常繁重的数字运算这是一个瓶颈,那么 LINQ 可能会出现问题 - 对其进行分析。
您可以用来支持 LINQ 的一个论点是,虽然您可以使用手写代码胜过它,但 LINQ 版本可能更清晰且更易于维护 - 此外,与复杂的手动并行化相比,PLINQ 还具有优势。
【讨论】:
+1 表示“过早悲观”【参考方案6】:这种比较的问题在于它在抽象中毫无意义。
如果一个人开始通过 MyLinqTestClass1 对象的 Name 属性对它们进行散列,则可以击败其中任何一个。在这两者之间,如果可以按名称对它们进行排序,然后再进行二进制搜索。实际上,我们不需要为此存储 MyLinqTestClass1 对象,我们只需要存储名称即可。
内存大小有问题?也许将名称存储在 DAWG 结构中,组合足够,然后将其用于此检查?
设置这些数据结构的额外开销是否有意义?这是不可能的。
另外一个问题是 LINQ 的概念存在不同的问题,这就是它的名称。对于营销目的来说,MS 能够说“这里有一堆很酷的新东西可以一起工作”,但当人们在进行应该将它们分开的分析时将它们组合在一起时就不那么好了.你必须打电话给Any
,它基本上实现了.NET2.0 时代常见的过滤器可枚举模式(并且在.NET1.1 中并不为人所知,尽管编写起来更尴尬意味着它只在它的地方使用在某些情况下,效率优势确实很重要),你有 lambda 表达式,你有查询树在一个概念中组合在一起。哪个慢?
我敢打赌,这里的答案是 lambda 而不是 Any
的使用,但我不会下很多赌注(例如项目的成功),我会测试并确定。同时,lambda 表达式与 IQueryable 一起工作的方式可以生成特别高效的代码,如果不使用 lambda,则很难以同等效率编写。
当 LINQ 因未能通过人工基准测试而提高效率时,我们不会变得高效吗?我不这么认为。
在有意义的地方使用 LINQ。
在瓶颈条件下,然后移开或使用 LINQ,尽管它似乎适合或不适合作为优化。不要先写难以理解的代码,因为你只会让真正的优化变得更加困难。
【讨论】:
这让我想起了 Juval Lowy 的“每个班级都作为 WCF 服务”的演讲。他就如何使用这种类型的场景(使用原始循环)来比较性能进行了有根据的长篇大论,不仅没有意义,而且与现实世界的测量结果相比,通常会产生错误的结果。【参考方案7】:也许 linq 很慢,但使用 linq 我可以非常简单地并行化我的代码。
像这样:
lst1.Cast<MyLinqTestClass1>().AsParallel().Any(item => item.Name == "9999");
你将如何并行化循环?
【讨论】:
实际上他们也不允许并行 linq,因为它的 linq 可能会遇到同样的性能问题。 @user455095 - 除了在许多情况下,并行 LINQ 与非 LINQ 相比实际上可以大大加速处理。当然,您可以自己实现线程化并最终得到 20 行代码,而不是 1 行。 @user455095:快速代码的线性执行几乎肯定比稍微慢代码的并行执行慢 我不完全同意@ck,因为有时并行执行的收益很小(当某些事情迫使它不是真正并行时),但总的来说这是真的。所以,@ user455095 你不允许使用更有效的方法,因为它的一部分效率低于效率较低的方法的一部分?对不起,那不是优化,那只是迷信。【参考方案8】:这是一个有趣的观察,因为您提到 nHibernate 由于 LINQ 很慢而变慢。如果您正在执行 LINQ to SQL(或 nHibernate 等效项),那么您的 LINQ 代码将转换为 SQL 服务器上的 EXISTS 查询,因为您的循环代码必须首先获取所有行,然后对其进行迭代。现在,您可以轻松编写这样的测试,以便循环代码读取所有 10K 运行的所有数据一次(单个 DB 查找),但 LINQ 代码实际上执行 10K SQL 查询。对于现实中不存在的循环版本,这可能会显示出很大的速度优势。实际上,单个 EXISTS 查询每次都会胜过表扫描和循环——即使您在被查询的列上没有索引(如果经常执行此查询,您可能会这样做)。
我并不是说您的测试就是这种情况——我们没有足够的代码可以查看——但它可能是。也可能是 LINQ to Objects 确实存在性能差异,但这可能根本不会转化为 LINQ to SQL。您需要知道您测量的是什么,以及它在多大程度上适用于您的实际需求。
【讨论】:
+1,很好地抓住了其他答案中没有提到的重要一点。 OP 不理解不同的实现会有不同的性能特征和考虑因素。【参考方案9】:对我来说,这听起来就像您正在签订一份合同,而雇主要么不了解 LINQ,要么不了解系统的性能瓶颈。如果您使用 GUI 编写应用程序,则使用 LINQ 对性能的轻微影响可以忽略不计。在典型的 GUI/Web 应用程序中,内存调用占所有等待时间的不到 1%。你,或者更确切地说是你的雇主,正试图优化这 1%。这真的有用吗?
但是,如果您正在编写一个面向科学或大量数学的应用程序,并且很少访问磁盘或数据库,那么我同意 LINQ 不是要走的路。
顺便说一句,不需要演员表。以下在功能上等同于您的第一个测试:
for (int i = 0; i < 10000; i++)
isInGroup = lst1.Any(item => item.Name == "9999");
当我使用包含 10,000 个 MyLinqTestClass1 对象的测试列表运行此程序时,原始运行时间为 2.79 秒,修改后的运行时间为 3.43 秒。在可能占用不到 1% 的 CPU 时间的操作上节省 30% 并不是很好地利用您的时间。
【讨论】:
它实际上是科学的并且对数学很重,并且考虑到在这些情况下可能应该避免它,但应该在任何地方应用它。我想你可以证明你可能需要在任何地方进行 10 亿次时间循环。 @user455095 -- 你的意思是,处理 10 亿个项目需要额外的 2.5 秒是不可接受的。如果他们担心这种程度的错误信息,那么您可能想从他们下面拉开地毯;看看使用 F#——如果这是科学/数学,那么 F# 可能会提供显着的优势 @user455095 - 我同意 STW。如果性能如此关键,那么完全放弃 C# 来处理繁重的数学例程并使用 GPU 或至少直接使用 C 将使他们受益。 我们实际上在 C++ 甚至 fortran 中有很多繁重的科学和数学例程。 @user455095 - LINQ 有时使代码更容易阅读,有时使编写速度更快。如果客户愿意为您编写代码支付更多费用,那么请务必放弃 LINQ。根据我的经验,简短的 LINQ 语句是一个巨大的好处,而长/复杂的语句会使代码更难理解。【参考方案10】:“[谁告诉我的?] 因为 .net linq 太慢了[为什么?] 我们不应该使用它”
根据我的经验,仅根据某人 曾经告诉你的内容来决定使用什么技术、库或语言是一个坏主意。
首先,信息是否来自您信任的来源?如果不是这样,那么相信这个(也许是未知的)人来做出你的设计决定,你可能会犯下一个巨大的错误。其次,这些信息今天仍然有用吗?但是好的,根据您的简单且不太现实的基准测试,您得出的结论是 LINQ 比手动执行相同的操作要慢。自然要问自己的问题是:此代码性能是否重要?除了我的 LINQ 查询的执行速度(想想数据库查询、等待 I/O 等)之外,此代码的性能是否会受到其他因素的限制?
这是我喜欢的工作方式:
-
确定要解决的问题,并根据您已知的要求和限制编写最简单的功能完整的解决方案
确定您的实现是否真正满足要求(是否足够快?资源消耗是否保持在可接受的水平?)。
如果是这样,您就完成了。如果没有,请寻找优化和完善您的解决方案的方法,直到它通过#2 的测试。这是您可能需要考虑放弃某些东西的地方,因为它太慢了。可能是。不过,瓶颈可能根本不在您的预期位置。
对我来说,这个简单的方法只有一个目的:最大限度地通过最大限度地减少我花在改进已经完全足够的代码上的时间。
是的,有一天您可能会发现原来的解决方案不再适用。或者它可能不会。如果是这样,那就当场处理它。我建议您避免浪费时间尝试解决假设的(未来)问题。
【讨论】:
嗯,首先不是推荐,它更像是一个规定的规则。如果您可以使用 foreach 而不是 linq 语句,那么为什么不使用它并且不冒险执行 linq 语句 10000 次,因为 foreach 可能被认为不那么复杂(不是我的话)。我想这个线程正在更多地转变为良好的编程实践,并且往往更加主观。如果你让 10 个程序员在一个房间里问他们的意见,你会得到什么? 10 种不同的意见......还有很多争论......我开始听起来有点愤世嫉俗。 @user: “如果您可以使用foreach
而不是LINQ 语句,那么为什么不使用[foreach
语句] 而不冒险[...]? " - 我不使用foreach
语句的原因是,在权衡由于编写笨拙的命令式代码而最终引入错误的风险时,性能问题的风险非常小。编写一个不起作用的快速程序很容易。修复快速但错误的程序也比加速慢但正确的程序更难。
@user455095:我不知道有一条“规定的规则”,即编写代码时应以执行速度为主要考虑点。当然,在某些特定的情况下,执行速度应该优于清晰和简单(想想游戏、国际象棋引擎、压缩代码等)。但是,根据我的经验,通过专注于功能而不是痴迷于速度,您将大大增加交付优质产品的机会。 @Aaronaught:说得很好——你很好地表达了我想要表达的观点。【参考方案11】:
是的,你是对的。在 LINQ 中编写慢代码很容易。其他人也是对的:在没有 LINQ 的情况下用 C# 编写慢代码很容易。
我用 C 编写了与您相同的循环,它的运行速度快了几毫秒。我由此得出的结论是 C# 本身很慢。
与您的 LINQ->loop 扩展一样,在 C 中,执行相同操作所需的代码行数是其 5 倍以上,这使其编写速度更慢、更难阅读、更容易出现错误和更难找到并修复它们,但如果为每十亿次迭代节省几毫秒很重要,那通常就是它所需要的。
【讨论】:
【参考方案12】:正如您所演示的,可以编写性能优于 LINQ 代码的非 LINQ 代码。但反过来也是可能的。鉴于 LINQ 可以提供的维护优势,您可能会考虑默认使用 LINQ,因为您不太可能遇到任何可归因于 LINQ 的性能瓶颈。
也就是说,在某些情况下 LINQ 无法正常工作。例如,如果您要导入大量数据,您可能会发现执行单个插入的操作比将数据以 XML 批量发送到 SQL Server 的速度要慢。在此示例中,并不是说 LINQ 插入比非 LINQ 插入快,而是不建议为批量数据导入执行单独的 SQL 插入。
【讨论】:
【参考方案13】:我宁愿说你应该避免过于努力地编写最有效的代码,除非它是强制性的。
【讨论】:
【参考方案14】:鉴于 LINQ 很慢,因此 PLINQ 很慢,而 NHibernate LINQ 也很慢,因此不应使用任何类型的 LINQ 语句。
这是一种不同的上下文,但令人难以置信的不同。当您谈论数据访问操作时,整个 10 亿次操作的 1.4 秒与 5 秒是无关紧要的。
【讨论】:
【参考方案15】:您的测试用例有点歪斜。 ANY 运算符将开始枚举您的结果,如果找到并退出,则在第一个实例上返回 true。尝试使用简单的字符串列表来查看结果。要回答有关避免使用 LINQ 的问题,您应该真正过渡到使用 LINQ。除了编译时检查之外,它还使代码在执行复杂查询时更易于阅读。此外,您不需要在示例中使用 Cast 运算符。
string compareMe = "Success";
string notEqual = "Not Success";
List<string> headOfList = new List<string>();
List<string> midOfList = new List<string>();
List<string> endOfList = new List<string>();
//Create a list of 999,999 items
List<string> masterList = new List<string>();
masterList.AddRange(Enumerable.Repeat(notEqual, 999999));
//put the true case at the head of the list
headOfList.Add(compareMe);
headOfList.AddRange(masterList);
//insert the true case in the middle of the list
midOfList.AddRange(masterList);
midOfList.Insert(masterList.Count/2, compareMe);
//insert the true case at the tail of the list
endOfList.AddRange(masterList);
endOfList.Add(compareMe);
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
headOfList.Any(p=>p == compareMe);
stopWatch.ElapsedMilliseconds.Dump();
stopWatch.Reset();
stopWatch.Start();
midOfList.Any(p=>p == compareMe);
stopWatch.ElapsedMilliseconds.Dump();
stopWatch.Reset();
stopWatch.Start();
endOfList.Any(p=>p == compareMe);
stopWatch.ElapsedMilliseconds.Dump();
stopWatch.Stop();
【讨论】:
【参考方案16】:类型转换当然会减慢您的代码速度。如果您那么在意,至少使用强类型的 IEnumerable 进行比较。我自己尽可能地尝试使用 LINQ。它使您的代码更加简洁。不必担心代码的必要细节。 LINQ 是一个函数式概念,这意味着您将说明您想要发生的事情,而不用担心如何发生。
【讨论】:
【参考方案17】:避免使用 Linq 的理由要好一千倍。
以下是关于 Linq 讨论的引用:
QUOTE1
“例如这有效:
var a = new x = 1, y = 2 ;
a = new x = 1, y = 3 ;
但这不起作用:
var a = new x = 1, y = 2 ;
a = new x = 1, y = 2147483649 ;
它返回:Error 1 Cannot implicitly convert type 'AnonymousType#1' to 'AnonymousType#2'
但这有效:
var a = new x = 1, y = 2147483648 ;
a = new x = 1, y = 2147483649 ;
编译时:
var a = new x = 1, y = 2 ;
x 和 y 分量的类型被任意声明为 32 位有符号整数,它是平台拥有的众多整数类型之一,没有任何特殊。
但还有更多。例如这有效:
double x = 1.0;
x = 1;
但这不起作用:
var a = new x = 1.0, y = 0 ;
a = new x = 1, y = 0 ;
数值转换规则不适用于此类类型。如您所见,优雅体现在每个细节中。”
QUOTE2
“那么,‘AnonymousType#1’和‘AnonymousType#2’似乎不是同义词——它们命名不同的类型。因为 x = 1, y = 2
和 y = 2, x = 1
分别是这两种类型的表达式,而不是它们不仅表示不同的值,还表示不同类型的值。
所以,我的偏执是对的。现在我的妄想症进一步扩大,我不得不问 LinQ 对以下比较有何看法:
new x = 1, y = 2 == new x = 1, y = 2
结果为假,因为这是一个指针比较。
但是结果:
(new x = 1, y = 2 ).Equals(new x = 1, y = 2 )
是真的。
结果:
(new x = 1, y = 2 ).Equals(new y = 2, x = 1 )
和
(new x = 1, y = 2 ).Equals(new a = 1, b = 2 )
是假的。”
QUOTE3
"更新是面向记录的:-O
我同意,这是有问题的,并且源于 LINQ 面向序列的性质。
这对我来说是一个表演终结者。如果无论如何我都必须使用 SQL 进行更新,为什么还要为 LinQ 烦恼?
LinQ 中不存在对对象的优化。
没有任何代数优化或自动表达式重写。许多人不想使用 LinQ to Objects,因为它们会损失很多性能。查询的执行方式与您编写查询的方式相同。”
【讨论】:
这与 LINQ 有什么关系?当然,LINQ 中使用了匿名类型,但它们不是 LINQ。 你又来了。除了巨魔软件问答网站,您还有什么可做的吗? 你的理由只有在你不知道自己在做什么的时候才有效。有经验的程序员不会/不会遇到这些问题,因为他们会知道他们的类型是如何工作的。 显然不可能获得负面声誉。 SO是否具有“透支”功能,因此所有这些反对票在未来实际上都算在内? :) 虽然我没有受过足够的教育,无法在这场辩论中表明立场,而且我非常喜欢使用 LINQ 并研究 LINQ 表达式 API 以及编写 LINQ 提供程序以进行实践,但我确实相信这张海报使一些非常有趣和有效的观察。这并不是说我不同意相反的论点。我实际上同意 Eric Lippert 和 Jon Skeet 所说的一切。即便如此,我只是发现这个人的帖子是一个聪明的同化,可悲的是,我怀疑是出于暴民的反应(当已经有另一个反对票时,你反对了),没有引起注意。以上是关于是否应该避免使用 LINQ,因为它很慢? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章