当前位置:首页 > Windows程序 > 正文

建议28:理解延迟求值和主动求值之间的区别

2021-03-27 Windows程序

建议28:理解延迟求值和主动求值之间的区别

要理解延迟求值(lazy evaluation)和主动求值(eager evaluation),先看个例子:

List<int> list = new List<int>() { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; var temp1 = from c in list where c > 5 select c; var temp2 = (from c in list where c > 5 select c).ToList<int>(); list[0] = 11; Console.Write("temp1: "); foreach (var item in temp1) { Console.Write(item + " "); } Console.Write("\ntemp2: "); foreach (var item in temp2) { Console.Write(item + " "); }

输出:

temp1: 11 6 7 8 9
temp2: 6 7 8 9

在延迟求职的情况下,只是定义了一个查询,而不是立刻执行。对查询结果的访问每次都会遍历原集合。如上文中对temp1的迭代,在迭代前,我们修改了list[0]的值,可见,修改直接影响了迭代的输出。对查询调用ToList、ToArray等方法,将会使其立即执行,由于对于list[0]的修改是在temp2查询之后进行的,所以针对list[0]的修改不会影响到temp2的结果。

在使用LINQ to SQL 时,延迟求值能带来显著的性能提升。例如:若果定义了两个查询,而且采用延迟求值,,CLR则会合并两次查询并生成一个最终的查询:

static void Main(string[] args) { DataContext ctx = new DataContext("server=192.168.0.102;database=Temp;uid=sa;pwd=sa123"); Table<Person> persons = ctx.GetTable<Person>(); var temp1 = from p in persons where p.Age > 20 select p; //省略 var temp2 = from p in temp1 where p.Name.IndexOf(e) > 0 select p; foreach (var item in temp2) { Console.WriteLine(string.Format("Name:{0}\tAge:{1}", item.Name, item.Age)); } } [Table(Name = "Person")] class Person { [Column] public string Name { get; set; } [Column] public int Age { get; set; } }

注意:这段代码需要SQL Server数据库的支持。本段代码假设已经存在一个Temp的数据库,其中有一个Person表,表内含有两个字段:

Name , varchar(50)

Age , int

迭代开始的时候,LINQ to SQL 引擎会生成如下SQL查询语句:

exec sp_executesql N‘SELECT [t0].[Name], [t0].[Age]

FROM [Person] AS [t0]

WHERE ((

  (CASE

    WHEN (DATALENGTH(@p0) / 2) = 0 THEN CONVERT(BigInt,0)

    ELSE CONVERT(BigInt,(CONVERT(Int,CHARINDEX(@p0, [t0].[Name])))-1)

  END)) > @p1) AND ([t0].[Age]>@p2)‘,N‘@p0 nchar(1),@p1 int,@p2 int‘,@p0=N‘e‘,@p1=0,@p2=20

最终的SQL语句合并了对年龄和姓名条件的查询。

如果Person表中的值如下:

根据上面查询将返回:

Name:Steve  Age:21

Name:Jessica  Age:22

如果采用主动求值:

var temp1 = (from p in persons where p.Age > 20 select p).ToList<Person>(); //省略 var temp2 = from p in temp1 where p.Name.IndexOf(e) > 0 select p;

会生成下面的语句:

exec sp_executesql N‘SELECT [t0].[Name], [to].[Age]

FROM [Person] AS [t0]

WHERE [t0].[Age]>@p0‘,N‘@p0 int‘,@p0=20

数据库会返回3条数据

Name:Steve  Age:21

Name:Jessica  Age:22

Name:Lisa  Age:23

虽然temp2的查询返回的结果也是两条记录,但是针对temp2的查询实际是对已经返回到本地的3条数据进行的筛选。这个例子中,返回3条或2条带来的效率问题并不明显,但是,将应用放到互联网系统中,每个地方减少一定的流量,则会给我们带来可观的性能提升。

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/68449.html