短路逻辑和延迟加载

简介:

一、短路逻辑

短路逻辑(short-circuit logic)也叫懒惰求值(lazy evaluation),在我们熟知的布尔运算中有一个非常有趣的特性:只有在需要求值时才进行求值。举例来说,ConditionA() and ConditionB()需要两个条件都为真时才是真,所以如果ConditionA() 为假,表达式立刻返回false,而不会去计算ConditionB()造成不必要的运算浪费。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static  void  Main( string [] args)
{
     if  (ConditionA() && ConditionB())
     {
         System.Console.WriteLine( "ConditionA() && ConditionB() is true" );
     }
     System.Console.WriteLine( "short-circuit logic test end" );
     System.Console.Read();
}
 
static  bool  ConditionA()
{
     System.Console.WriteLine( "ConditionA:false" );
     return  false ;
}
 
static  bool  ConditionB()
{
     System.Console.WriteLine( "ConditionB:true" );
     return  true ;
}

输出:

ConditionA:false

short-circuit logic test end

如你看到的那样,ConditionA()为假,那么ConditionB()就被“短路”了,根本不需要去执行。这种“只有在需要求值时才进行求值”的特点体现了“按需”的思想,可以看做是一种朴素的延迟加载。

 

二、延迟加载(执行)

在实际开发中延迟加载的思想应用非常普遍,比如图片的按需加载、某些ORM实现的查询对关联数据的加载等等。那么什么是延迟加载呢?

百度百科解释的超级烂,但是我们都可以理解,延迟加载体现了“按需创建要使用的资源”这一核心思想。在.NET中有不少按需分配(Load On Demand)延迟加载的实现机制。下面结合实际开发试举两个常见的延迟加载的例子。

1、yield和Linq

yield关键字的使用记得以前总结过,可参考这一篇

yield语句只能出现在iterator(迭代器)块中,我们可以把一些耗时的或者需要延迟的操作放在MoveNext()里面。正是yield才使Linq的延迟执行成为可能。

在Linq中,所有实现了IEnumerable<T>接口的类都被称作sequence(序列),Linq最基本的数据单元是sequences和elements。一个sequence是实现了IEnumerable<T>的对象,而一个element是sequence中的每一个元素。如下就是一个简单的Linq查询:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class  UserInfo
{
     public  string  Name { get ; set ; }
}
 
class  Program
{
     static  void  Main( string [] args)
     {
         var  lang = "python" ;
         var  list = new  List<UserInfo> {
             new  UserInfo{Name= "jeffwong" },
             new  UserInfo{Name= "anytao" },
             new  UserInfo{Name= "dudu" }
         };
         var  query = list.Where(m => m.Name.StartsWith( "j" )); //linq查询
         if  (lang == "c#" )
         {
             foreach  ( var  item in  query)
             {
                 Console.WriteLine(item.Name);
             }
         }
         System.Console.Read();
     }
}

上面示例代码中有个if条件,就是当语言(lang)等于C#的时候输出序列中的用户(元素)的名称。但是其实这个条件为假,所以对于linq查询结果query根本没有什么作用,如果这是一个耗时的查询操作,偏偏查询结果又用不到,那不是白做了吗?好在在Linq查询实现中,query变量只是一个可迭代列表(IEnumerable<T>)对象占位符,它根本没有进行计算,也没有加载数据(这里是用户信息)进入内存,只有在foreach遍历取值的时候才会进行运算取值,显然可以节省开销。

当然,上例中我们构造的列表数据量很小,而且本身就在内存中,就算执行了查询,好像也看不出性能上有多少提升。但是实际上在我们熟知的Linq to Sql中,IQueryable<T>就是继承实现了IEnumerable<T>接口,使用Linq To Sql访问数据库,对于网络传输和IO的影响就不得不考虑,否则很容易造成查询缓慢用户体验恶劣。好在我们可以利用Linq的延迟执行机制写出良好的查询,而且微软的Linq To Sql和ADO.NET Entity Framework框架都支持对关联数据的延迟加载机制。

 

2、Lazy<T>

.NET中典型的延迟加载按需创建对象的类就是Lazy<T>,对于那种“懒对象”的创建非常简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class  UserInfo
{
     public  string  Name { get ; set ; }
}
 
class  Program
{
     static  void  Main( string [] args)
     {
         Lazy<UserInfo> lazyUser = new  Lazy<UserInfo>(() => new  UserInfo { Name = "jeffwong"  });
         if  (!lazyUser.IsValueCreated) //用户还没有创建
         {
             Console.WriteLine( "User is not created yet." );
         }
         Console.WriteLine(lazyUser.Value.Name); //此时真正创建用户
         System.Console.Read();
     }
}

实际上Lazy<T>可以给开发者提供更多的控制选项(比如支持委托)和线程安全。






本文转自JeffWong博客园博客,原文链接:http://www.cnblogs.com/jeffwongishandsome/archive/2012/08/05/2623810.html,如需转载请自行联系原作者

目录
相关文章
|
9月前
逻辑判断使用
逻辑判断使用
27 1
|
7月前
关于短路操作
在逻辑与&& 或者 逻辑或 || 的运算中,表达式1满足要求,表达式2不再运算的操作即为短路操作
25 0
|
8月前
清水混毒【逻辑题】
清水混毒【逻辑题】
50 0
|
9月前
|
数据采集 安全 程序员
逻辑是个好东西
这些逻辑关系、推导过程与程序中的逻辑结构息息相关。如果你对此不能保持思路清晰,写出的代码很可能与预期有出入,或是在一些特殊情况下存在漏洞。
|
10月前
逻辑操作符的短路现象
逻辑操作符的短路现象 1.逻辑操作符 2.逻辑操作符的短路
51 0
逻辑门电路
随着新技术的发展,集成数字电路类型层出不穷,大量使用大规模功能模块已成为现实。数字电路在众多领域已取代模拟电路,可以肯定,这一趋势将会继续发展下去。 一、逻辑门电路是什么? 逻辑门电路可以分为基本逻辑门和复合逻辑门。具体如何,让我们接下来去了解什么是基本逻辑门,什么是复合逻辑门?
170 0
逻辑门电路
|
Java 编译器 C语言
C++中尽量少做类型转换动作
C++中尽量少做类型转换动作
250 0
逻辑运算的短路特性(&&,||)
逻辑运算的短路特性(&&,||)
190 0
|
Go 索引
SolrCore getSearcher逻辑回顾
假期重新把之前在新浪博客里面的文字梳理了下,搬到这里。
129 0