您的位置:首页 > 编程语言 > Lua

More Effective C++ 条款17 考虑使用lazy evaluation(缓式评估)

2015-09-22 22:17 369 查看
1. lazy evaluationg实际上是"拖延战术":延缓运算直到运算结果被需要为止.如果运算结果一直不被需要,运算也就不被执行,从而提高了效率.所谓的运算结果不被执行,有时指只有部分运算结果被需要,那么采用拖延战术,便可避免另一部分不被需要的运算,从而提高效率,以下是lazy evaluation的四种用途.

2. Reference Counting(引用计数)

如果要自己实现一个string类,那么对于以下代码:

String s1="Hello";
String s2=s1;


最直接的是采用eager evalutation(急式评估):为s1做一个副本并放入s2内,尽管此时s2的内容和s1并没有不同.

采用lazy evaluation的思想,可以先让s2分享s1的值,这样就省去了"调用new"以及"复制任何东西"的高昂成本.唯一要做的是一些簿记工作,以记录共享同一内容的各个对象.对s2的任何读操作,只需要s1的值即可,然而,一旦需要对s2的值进行写操作,就不能再做任何拖延,必须为s2做一份真实副本并进行写操作.

这种"数据共享"的观念就是lazy evaluation:在真正需要之前,不为对象构造副本.在某些应用领域,可能永远也不需要提供那样一份副本,从而提高效率.

3. 区分读和写

承接于2的策略,如果对自定义的string类进行以下操作:

Matrix m4(1000,1000);
...
m3=m4*m1;


View Code
那么便可直接将m3定位为m4和m1的乘积,之前没有用到的矩阵加法操作实际上并没有进行.当然,对m1和m2加和却没有用到的情况比较夸张,但不排除维护过程中程序员更改代码使得m1+m2不被用到的请况出现.

当然,lazy evaluation在此处还有更大用法——只计算大型运算中需要的部分运算结果.

对于以下代码:

cout<<m3[4];


此时不能再使用拖延战术,但也只需要计算m3第四行的值,除此以外,不需要计算其他任何值.实际上,正是这种策略使得APL(20世纪60年代的一款如软件,允许用户以交谈方式使用软件执行矩阵运算)能够快速处理加法,减法,乘法甚至除法.

当然,有时lazy evaluation并不能起作用,比如如下操作:

cout<<m3;


或者:

m3=m1+m2;
m1=m4;


这时就要采取某些措施以确保对m1的改变不会影响m3的值,可以在对m1进行改变之前先对m3求解,也可以将m1的旧值复制一份,然后令m3依从该值等,其他可能会修改矩阵值的情况,也要采取类似措施.

此外,由于存储数值间的相依关系,必须维护一些数据结构一存取数值,相依关系等,此外还必须将赋值,复制,加法等操作符进行重载,因此lazy evaluation用于数值运算领域也有许多工作要做,但与节省的时间和空间相比可能是微不足道的.

6. "Lazy evaluation在许多领域中都可能有用途:可避免非必要的对象复制,可区别operator[]的读取和写操作,可避免非必要的数据库读取动作,可避免非必要的数值计算动作."但其提升效率的前提是(部分)计算可能可以被避免,否则,在计算绝对必要的情况下,使用lazy evaluation不仅不能提升效率,还需要付出为lazy evaluation而设计的额外的数据结构等代价.

7. "Lazy evaluation并非C++的专属技能.这项技术可以用任何一种程序语言完成,有数种语言——APL,某些Lisp版本,以及几乎所有的数据流(dataflow)语言——已接受这个观念成为语言的一个基础部分."不过由于C++对封装性质的支持使得将lazy evaluation加入某个类内而对客户隐藏具体实现成为可能.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: