C#延迟执行
借鉴于该篇博客:http://kb.cnblogs.com/page/42581/
先看两个方法
public class YieldClasses
{ public static IEnumerable<int> WithNoYied()
{
List<int> list = new List<int>(); for (int i = 0; i < 100; i++)
{
Console.Write(i.ToString());
list.Add(i);
}
return list; } public static IEnumerable<int> WithYied()
{
for (int i = 0; i < 100; i++)
{
Console.WriteLine(i.ToString());
yield return i;
}
} }
分别用执行他们接过是怎样
YieldClasses.WithNoYied();
YieldClasses.WithYied();??????
令人惊讶的是:第一个函数跟预期的一样,从1输到99。而第二个函数却什么 也没有输出!这是神马回事???
我们再foreach中迭代两个函数
foreach (var item in YieldClasses.WithNoYied())
{
Console.Write(item.ToString()+"-");
}
结果:
withYied的结果
withnoYied的结果:
1233456789101112.。。。。。。。0-1-2-3-4-5-6-7-8-9-10.。。。(突然截图不行了)
这是神马回事呢?
从显示的结果可以看出,在WithNoYied中,是先循环执行完函数中的console.write,再执行main中的write
而在WithYied中,是循环一次,先执行函数中的wirte,再执行main中的write,再循环下一次。。。。
这就是症结所在!明之:yield的延迟执行!
http://kb.cnblogs.com/page/42581/2/ 这里有用IL的方法分析。我就简单的总结以下吧:
延迟计算(Lazy evaluation或delayed evaluation)在Wiki上可以找到它的解释:将计算延迟,直到需要这个计算的结果的时候才计算,这样就可以因为避免一些不必要的计算而改进性能,在合成一些表达式时候还可以避免一些不必要的条件,因为这个时候其他计算都已经完成了,所有的条件都已经明确了,有的根本不可达的条件可以不用管了。反正就是好处很多了。
延迟计算来源自函数式编程,在函数式编程里,将函数作为参数来传递,你想呀,如果这个函数一传递就被计算了,那还搞什么搞,如果你使用了延迟计算,表达式在没有使用的时候是不会被计算的,比如有这样一个应用:x=expression,将这个表达式赋给x变量,但是如果x没有在别的地方使用的话这个表达式是不会被计算的,在这之前x里装的是这个表达式。
延迟计算在linq中的应用:
看看下面的方法:
public static void LinqTest()
{
int[] intArray = {1,3,6,5,9,34 };
int a=0; var result = from item in intArray
select item;
if(a==0)
{
foreach(int i in result)
{
Console.Write(i);
}
}
}
这样的方法,如果a==0,那会输出结果(先执行linq操作),但如果a!=0,那么linq操作就不执行!
result是一个实现了IEnumerable接口的类(在Linq里,所有实现了IEnumerable接口的类都被称作sequence),对它的foreach或者while的访问必须通过它对应的IEnumerator的MoveNext()方法,如果我们把一些耗时的或者需要延迟的操作放在MoveNext()里面,那么只有等到MoveNext()被访问,也就是result被使用的时候那些操作才会执行,而给result赋值啊,传递啊,什么的,那些耗时的操作都没有被执行。
如果上面这段代码,最后由于state小于0,而对result没有任何需求了,在Linq里返回的结果都是IEnumerable的,如果这里没有使用延迟计算,那那个Linq表达式不就白运算了么?如果是Linq to Objects还稍微好点,如果是Linq to SQL,而且那个数据库表又很大,真是得不偿失啊,所以微软想到了这点,这里使用了延迟计算,只有等到程序别的地方使用了result才会计算这里的Linq表达式的值的,这样Linq的性能也比以前提高了不少,而且Linq to SQL最后还是要生成SQL语句的,对于SQL语句的生成来说,如果将生成延迟,那么一些条件就先确定好了,生成SQL语句的时候就可以更精练了。还有,由于MoveNext()是一步步执行的,循环一次执行一次,所以如果有这种情况:我们遍历一次判断一下,不满足我们的条件了我们就退出,如果有一万个元素需要遍历,当遍历到第二个的时候就不满足条件了,这个时候我们就可就此退出,后面那么多元素实际上都没处理呢,那些元素也没有被加载到内存中来。
延迟计算还有很多惟妙惟肖的特质,也许以后你也可以按照这种方式来编程了呢。写到这里我突然想到了Command模式,Command模式将方法封装成类,Command对象在传递等时候是不会执行任何东西的,只有调用它内部那个方法他才会执行,这样我们就可以把命令到处发,还可以压栈啊等等而不担心在传递过程中Command被处理了,也许这也算是一种延迟计算吧。
本文也只是很浅的谈了一下延迟计算的东西,从这里还可以牵扯到并发编程模型和协同程序等更多内容,由于本人才疏学浅,所以只能介绍到这个地步了,上面一些说法也是我个人理解,肯定有很多不妥地方,欢迎大家拍砖。
C#延迟执行的更多相关文章
- ThreadPoolTimer -延迟执行, 周期执行
介绍重新想象 Windows 8 Store Apps 之 线程池 通过 ThreadPoolTimer 实现延迟执行 通过 ThreadPoolTimer 实现周期执行 通过 ThreadPool ...
- 浅谈iOS开发中方法延迟执行的几种方式
Method1. performSelector方法 Method2. NSTimer定时器 Method3. NSThread线程的sleep Method4. GCD 公用延迟执行方法 - (vo ...
- LINQ之路 6:延迟执行(Deferred Execution)
LINQ中大部分查询运算符都有一个非常重要的特性:延迟执行.这意味着,他们不是在查询创建的时候执行,而是在遍历的时候执行(换句话说,当enumerator的MoveNext方法被调用时).让我们考虑下 ...
- IOS中延迟执行的几种方法
前几天去国美在线面试,就遇到了上面的问题,当时是笔试,只写出来了第一种方法,现在整理了一下. //1.performSelector方法:在当前线程中执行的方法,使用默认模式,并延迟执行@select ...
- js中的延迟执行和定时执行
在js中,延迟执行函数有两种,setTimeout和setInterval,用法如下: function testFunction(){Console.log('hovertree.com');} s ...
- iOS定时器、延迟执行
1.通用方式(并不是实时调用并且会卡顿): // 一般用于更新一些非界面上的数据 [NSTimer scheduledTimerWithTimeInterval:时间间隔 target:self se ...
- linq 延迟执行带来的困扰
有这样一个案例: var filteredResult = from f in orgFileList select f; ; i < WorkStatusFilters.ListWorkSta ...
- 重新想象 Windows 8 Store Apps (42) - 多线程之线程池: 延迟执行, 周期执行, 在线程池中找一个线程去执行指定的方法
[源码下载] 重新想象 Windows 8 Store Apps (42) - 多线程之线程池: 延迟执行, 周期执行, 在线程池中找一个线程去执行指定的方法 作者:webabcd 介绍重新想象 Wi ...
- Go defer延迟执行
defer用于延迟执行,可以类比于java或c++中的析构函数. 查看一段示例代码: func Contents(filename string) (string, error) { //打开文件 f ...
- SQL Server游标+延迟执行简介
在项目测试中,我们可能会使用批量生成数据来测试程序的性能. 这里讲一个我遇到的问题,由于我们批量生成数据时基本上是瞬间完成,所以GETDATE()函数获得的时间基本上也是一样的,而我们又要求生成每条数 ...
随机推荐
- GITBOOK/HEXO TRAVIS GITHUB-PAGES 博客搭建
简介 这年头要是没有个博客都不好意思给别人说你是程序员,我用XX笔记呀,不行吗?不行,这玩意儿要么不能公开分享,要么公开分享要会员,现在到处都是开源,自己学到了东西都不能分享给需要帮助的人,真是伤心呀 ...
- 为什么多线程读写 shared_ptr 要加锁?
https://www.cnblogs.com/Solstice/archive/2013/01/28/2879366.html 为什么多线程读写 shared_ptr 要加锁? 陈硕(giantch ...
- 匿名方法,lambad表达式,匿名类
其实lambad表达式就是“函数”或者说是“方法”写法的一个进化,越来越简化而已,如数学方法里的f(X). 匿名方法:顾名思义,匿名方法就是没有名称的方法,但是有定义参数. 匿名方法最明显的好处就是可 ...
- Django的路由层(URLconf)
URL配置(URLconf)就像Django所支撑网站的目录.它的本质是URL与要为该URL调用的视图函数之间的映射表:你就是以这种方式告诉Django,对于客户端发来的某个URL调用哪一段逻辑代码对 ...
- .net Reactor之限定日期内使用,限定使用次数,限定使用时间
.net Reactor之限定日期内使用,限定使用次数,限定使用时间 上一篇(https://www.cnblogs.com/s313139232/p/9908833.html)详细的记录了.net ...
- [转] C#实现在Sql Server中存储和读取Word文件 (Not Correct Modified)
出处 C#实现在Sql Server中存储和读取Word文件 要实现在Sql Server中实现将文件读写Word文件,需要在要存取的表中添加Image类型的列,示例表结构为: CREATE TABL ...
- android学习-Eclipse中修改Android项目图标
参考原文:http://blog.csdn.net/wpwbb510582246/article/details/52556753 方法一:替换res文件夹下的ic_launcher-web.png图 ...
- eclipse Oxygen 4.7 + pydev
pydev 官网 安装手册 PyDev requires Java 8 and Eclipse 4.6 (Neon) in order to run and only supports Python ...
- 让你的网站用上https
一般申请了SSL证书,会有安装教程教你一步步配置.这里照搬官方教程. 下载得到的 www.domain.com.zip 文件,解压获得3个文件夹,分别是Apache.IIS.Nginx 服务器的证书文 ...
- Excel VBA 获取按钮对象
今天给同事写了两个VBA宏,并分别把宏赋给了两个按钮. 因为两个宏都是实现在两种显示方式之间切换,于是我想除了功能的实现外,还希望在切换到其中一种方式时,按钮上面的文字也可以跟着改变,起到提示作用. ...