我目前正在一本 Nutshell书中阅读 Albahari 的C# 3.0,在第 292 页上它说关于 LINQ:
LINQ 遵循需求驱动的拉 模型,而不是供应驱动的 推模型。
上面的说法是什么意思?拉模型和推
模型
有什么区别?
我是客户,我需要一些东西,从服务器上拉出来。
我是服务器,我有东西,推送给客户端。
这意味着您的 LINQ 查询将根据您的查询从数据源中提取数据,并且只会在执行时完成。与推送模型相反,服务器在其末端生成数据,然后将数据推送到客户端。推送模型类似于 Blackberry Enterprise Server,其中电子邮件被推送到 Blackberry 设备,而不是设备不断地查询它。这也意味着自您的 LINQ 查询以来的任何更改都不会反映在您的数据集中。
要真正理解(并欣赏)区别,您需要考虑statement和expression之间的区别。如您所知,C# 和 VB 等命令式编程语言传统上使用按顺序执行的语句来完成某些目标。在这样的方案中,您检索数据,然后将其推送到其他一些语句中。相比之下,函数式编程倾向于使用表达式这只是价值观。在 LINQ 的情况下,您声明了一个查询表达式,该表达式在某些时候将评估为一个值,但直到需要它才会这样做。这让作为程序员的你可以更专注于你的程序做了什么,而不是它是怎么做的。更广泛地说,惰性描述了一种通常由函数式编程语言采用的评估策略。例如,如果您有如下声明:
let x = 2 * y + 7
惰性编程语言在明确需要之前不会打扰评估表达式,但同时您可以通过绑定x来引用它。同样,当您在 LINQ 中进行如下声明时:
var collection = from s in S where predicate(s)
您已经声明了一个表达式并将其绑定到collection ,但在您对collection执行某些操作之前,您实际上并不需要它。因此,您可以在代码中的任何位置声明它,而不必担心它在不使用时会占用内存,因此您现在更多地考虑您要解决的问题,而不是详细说明计算机应该如何运行关于解决它。
因此,总而言之,在(急切的)命令式编程风格中,您获取数据,然后将其推送到将对其起作用的某个函数上。在(惰性)函数式编程中,您声明一个表达式,并在需要时对其进行评估,这在数据库的情况下意味着需要查询表达式值的函数将在它时拉取它需要它。Push/Pull 确实是一个糟糕的术语。
在拉模型中,处理由结果的消费者发起(结果被“拉”通过处理管道)。
在推送模型中,处理由数据的生产者发起(数据被“推送”到处理管道中)。
因此,将要处理的数据是在任何一种情况下都会被处理的数据,并且它正在移动的“方向”(推/拉)是相对于触发处理的人而言的。