LINQ 的可扩展性如何? [关闭]

Posted

技术标签:

【中文标题】LINQ 的可扩展性如何? [关闭]【英文标题】:How scalable is LINQ? [closed] 【发布时间】:2010-09-17 20:56:36 【问题描述】:

最近与同事的对话对此事产生了不同的观点。 SO 成员,你们怎么说?

我知道,即使是可扩展性的概念也可以用许多不同的方式和背景来理解,但这是讨论的一部分。对于可扩展性的真正含义,每个人似乎都有不同的看法。我也很想看到这里的变化。事实上,我只是为了这个概念发布了question。

【问题讨论】:

【参考方案1】:

我猜想最好的检查方法是编写基准测试,但我认为 LINQ 具有优化手写类似代码所没有的可能性。我不知道它如何利用这些优势。

LINQ 让您表达您想要的,而不是如何生成它。一个明显的优势是 LINQ 可以自动并行化(请参阅PLINQ)。

LINQ 的另一个优点是它是惰性的,因此您可以执行计算,根据需要从集合中绘图。您可以手动编写等效代码,但在 LINQ 中正确编写可能要容易得多。

【讨论】:

LINQ 的另一个缺点是它很懒惰,当您可以一次完成所有数据时,您不希望昂贵的旅行来获取数据。它的所有摆动 n 回旋处。 @gbjbaanb:您可以通过调用 ToX 方法来强制执行 eval。【参考方案2】:

在我们进行的测试中,LINQ to objects (ForEach) 比 foreach 循环慢了大约 2 倍。

LINQ to SQL(MS SQL 数据库)几乎比使用数据读取器直接查询慢 10 倍,大​​部分时间使用从表达式树创建 SQL(因此,您将受 CPU 限制和数据库会闲置) 为避免这种情况,您必须使用已编译的查询。

See this 了解更多。帖子中的大部分信息在 .NET 3.5 SP1 中仍然有效。

【讨论】:

我很想看到您的测试使用预编译的 LINQ 查询重新运行,就像它们在任何生产环境中一样。【参考方案3】:

这个问题有点像问“集合的可扩展性如何?”

让我们来谈谈 LINQ to 对象。一般而言,就IEnumerable<T> 的大多数实现迭代基础集合中的每个项目而言,LINQ 具有很大的扩展潜力。创建一个包含一千万个项目的List<Foo>,如下所示:

var list = from Foo f in fooList
           where f.Value = "Bar"
           select f;

会很慢。但这真的不是 LINQ 的错。是你给了它一千万个项目的清单。

如果 LINQ 不存在,您会以同样的方式处理这个问题:通过构建字典和 SortedLists 等来帮助您减少搜索空间。

LINQ 可以通过延迟查询执行改进可伸缩性(嗯,使可伸缩性更容易获得)。您可以用一系列 LINQ 查询替换创建列表、将其过滤到新列表、将其过滤到新列表等的简单方法:

var list1 = from Foo f in fooList where f.Value1 = "Bar" select f;
var list2 = from Foo f in list1 where f.Value2 = "Baz" select f;
var list3 = from Foo f in list2 where f.Value3 = "Bat" select f;

当(并且如果)有必要遍历最终列表时,所有这些都将在一次遍历基础集合中执行。不过,这又不是什么新鲜事:如果您没有 LINQ,您可能最终会用做同样事情的方法替换您的幼稚方法。但是 LINQ 让它变得容易得多。

【讨论】:

您是说通过构建数据的字典和排序列表来提高 1000 万个项目表的性能吗?你不应该优化数据库(索引等)而不是这个实例中的代码吗? 他当然不是这么说的,内森——他是在说明 linq 与其他查询集合的方式相比。 我说的是内存中的对象集合,而不是数据库中的行。构建字典/排序列表添加索引。【参考方案4】:

在我看来,LINQ 旨在从开发的角度简化事情,而不是解决可伸缩性问题。

事实上,使用 LINQ 可以让事情变得如此简单,因为它隐藏了很多复杂性,并且可能在使用时不负责任地导致可伸缩性问题。

其他答案中的例子比比皆是,但最重要的是:

如果您正在查询对象集合,则不能忽略其大小。当有几个对象要查询时,也许在模型中使用 LINQ 听起来不错……但随着大小的增长,很明显查询应该发生在数据库中,而不是模型中。

如果您使用 LINQ 自动生成 SQL,据我所知,您无法为数据库提供有关如何编译查询的提示,例如 WITH (NOLOCK)。随着您的表大小增加,能够解决这些问题势在必行。

与上述类似,但可能更笼统:当您解决数据库的可伸缩性问题时,您必须控制数据库正在做什么。拥有一种可以编译为 SQL 的语言,然后再将其编译为一个执行计划,这样就可以从你的手中移除控制权。

如果您必须更改数据库架构以使其更具可扩展性,并且您的代码与它紧密相关,因为您没有存储过程,会发生什么情况?

虽然看起来很简单,但更改 LINQ 提供程序会很痛苦:查询 SQL Server 与查询对象或查询 XML 不同。 LINQ 非常相似。我确实希望我的一些初级开发人员继续“LINQ 狂欢”,因为这比学习如何在考虑可扩展性的情况下做事更容易。

总之,我认为使用 LINQ 编写可扩展的代码是可能的,但必须小心使用它。没有杀手工具,只有杀手代码

【讨论】:

没有NOLOCK?哎呀!我想那时也没有 SET NOCOUNT? 在说不可能之前应该先寻找答案:hanselman.com/blog/… @sirroco - 在 Scott 提出的三种方法中,让您真正拥有“NOLOCK”的唯一方法是“编写一个存储过程并将其放入其中”。哇。我的观点是正确的。【参考方案5】:

这很大程度上取决于您使用的是哪个 LINQ 提供程序以及您如何使用它。 LINQ 可能并不以惊人的执行速度着称,而是为开发人员提供了更好的生产力。

根据this 链接,即使使用某些 CTP,Linq to SQL 在某些情况下已经比使用直接 SQL 更好。

如果您关心速度并且大量使用 LINQ to objects here 是一个 codeplex 项目(我认为),它可以为您提供 1000 倍的性能改进。

【讨论】:

LINQ to SQL 到底怎么可能比直接 SQL 更快?它不能这是更新语句的苹果和橘子比较。 不确定你所说的更新的苹果和橙子是什么意思。他们完全不同?平均查询可以通过 ORM 层进行部分优化,执行高级缓存和查询批处理以获得额外的可伸缩性。如果您要手工制作,这些都需要手工完成。【参考方案6】:

您在某些方面关于可伸缩性的问题取决于您使用 LINQ 的目的。在业务应用程序中,您不会发现很多 SQL 命令正在执行——它们很慢并且必须在 DBMS 中编译。相反,您将看到大量存储过程调用。这些在 LINQ 中会稍微快一些。

请记住,LINQ to SQL 等是基于 ADO.NET 的 TOP 构建的——它们并不是完全不同的方法或任何东西。当然,LINQ to XML 将在幕后使用不同的 API。这将很像一个编译器——人类总是可以做出一些可能更快的优化,但在大多数情况下,这些 API 将能够生成比您自己编写的代码更快且错误更少的代码。

在横向扩展方面,如果您想稍微分发数据,或者您可以使用 SQL 服务器复制,则始终可以将 LINQ 置于 Web 服务之后。它的可扩展性不应低于 ADO.NET。

【讨论】:

【参考方案7】:

可扩展性和性能是两个不同但相关的东西。如果要衡量性能,则需要查看一个盒子可以支持多少用户(例如)。当您测量可扩展性时,您添加另一个盒子,看看您是否可以支持原始数量的两倍?不太可能,你可能只增加了 75% 的处理能力,下一个只增加了原始单位的 50%,所以它很快就降到了零。无论您以该速度添加多少个框,您都很幸运能够将您支持的用户数量翻倍。这就是可扩展性。

您的 Linq 模块如何扩展可能更多地取决于数据库、机器的强大程度、数据库的设计以及您的应用程序的设计。

您经常会看到本应揭示结论性内容的微观基准,但它们从来没有这样做,因为它们只是对整个问题的关键洞见。

您可以在此处提取旧的 20/80 示例。可能 20% 与工具有关,80% 与构成您的应用程序的各种有形物有关。

【讨论】:

【参考方案8】:

如果您正在寻找现实生活中的示例,*** 大量使用 Linq,请查看此post/podcast。

【讨论】:

我们实际上移除了它是因为它的可扩展性,尽管它仍然隐藏在几个地方,因为移除它太讨厌了【参考方案9】:

使用 Linq to SQL 框架按需缓存和加载对象是有代价的。 如果一个对象可以按需延迟加载其自身的一部分,那么很可能每个对象中都存在对数据上下文的引用。顺便说一句,数据上下文还缓存了曾经从它请求过的每个对象。这意味着,如果您保留其中一个对象(在缓存中或只是因为您稍后使用它),您不仅保留了该对象,而且保留了数据上下文所请求的每个对象。这些将永远不会被垃圾收集,因为它们仍在被引用。

如果所有目标的生命周期都很短,并且应用程序每次执行新工作时都会创建新的 DataContext,这不是问题。但是我可以看到,如果有人不知道每个对象都会带来额外的负担,它会如何产生可伸缩性问题。

【讨论】:

【参考方案10】:

Linq 在很多方面都是可扩展的。

一个方面是 linq 背后的规范实现,它允许 Expression 被解释为在进程外运行,使用不同的语言(Linq2Sql,Linq2Hibernate),或者在分布式计算环境中,例如 map-reduce 集群( DryadLINQ)

另一个方面是 linq 为语言提供的语义。如果您的提供程序支持延迟加载,或者您可以并行化或优化查询(PLINQ 或 i4o),您可以遍历数十亿个对象而无需将集合填充到内存中。

【讨论】:

以上是关于LINQ 的可扩展性如何? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

可枚举的 LINQ 扩展隐藏在字符串中......为啥以及如何? [复制]

扩展方法和Enumerable

如何使用 linq lambda 扩展方法执行带有 where 子句的左外连接

如何使用扩展在Linq Lambda中编写此SQL

您最喜欢的非内置 LINQ to Objects 运算符是啥? [关闭]

Linq 中默认值的平均扩展方法