18 分期摊还期望的计算

核心条款——over-eager evaluation(过度热情计算法) :在要求你做某些事情之前就完成它们。

例如下面模板类,用来表示大量数字类型的集合:

template<class NumericalType>
class DataCollection
{
public:
	NumericalType min() const;
	NumericalType max() const;
	NumericalType avg() const;
};

 

假如min,max和avg函数分别返回现在这个集合的最小值,最大值和平均值。有三种方法实现这个函数:使用eager evaluation(热情计算法),当min,max和avg函数被调用的时,我们检测集合内所有的数值,然后返回一个合适的值。使用lazy evaluation(懒惰计算法),只有确认需要函数的返回值的时,我们才要求函数能返回能用来确定准确数值的数据结构。使用over-eager evaluation(过度热情计算法),我们随时跟踪目前集合的最小值,最大值和平均值,这样min,max和avg被调用时,我们不用再计算就能立刻返回正确的值。如此频繁调用min,max和avg,我们把跟踪集合最小值,最大值和平均值的开销分摊到所有这些调用函数,每次函数调用索分摊的开销比eager evaluation或lazy evaluation要小。

 

采用over-eager 最简单的方法是caching(缓存)那些已经计算出来而以后还要可能需要的值。

例如如下代码:你编写一个程序,用来提供有关雇员的信息,这些信息中的经常被需要的部分是雇员的办公隔间号码。假设雇员信息存储在数据库中,但是对于大多数应用程序来说,雇员隔间都是不相关的,所以数据库不对查抄它们进行优化,为了避免你的程序给数据库造成负担,可以编写一个函数findCubicleNumber用来缓存数据。每次查找直接在cache中查找,而不是数据库。

 

int findCubicleNumber(const string& employeeName)
{
	typedef map<string,int> CubicleMap;
	static CubicleMap cubes;
	
	CubicleMap::iterator it = cubes.find(employeeName);
	if(it  == cubes.end())
	{
		cubes[employeeName] = cubicle;	//没找到就插入,再返回当前
		return cubicle;
	}else
		return it->second;				//找到直接返回
	
}

Prefetching(预提取)则是另外一个方法。

例如你又一个dynamic数组数显的模板,dynamic就是开始时具有一定尺寸,以后可以自动扩展的数组。所以所有非负的索引都是合法的:

 

template<class T>
class DynArray{...}; //dynamic数组的模板

DynArray<double> a; //此时,只有a[0]是合法的数组

a[22] = 3.5;		 //索引0-22是合法的数组

a[32] = 0;			//索引0-32是合法的数组

一个DynArray对象在需要的时候自行扩展?一种最直接的方法按需要分配内存:

 

template<class T>
T& DynArray<T>::operator[](int index)
{
	if(index < 0)
		throw an exception;
	
	if(index > 当前最大的索引值)
		调用new分配足够的额外内存,以使得索引合法;
	
	返回index位置上的数组元素;
}

每次增加数组长度时,这种方法就要调用new,调用new会触发operator new,operator new调用开销大,因为导致底层操作系统的调用,系统调用的速度一般比进程内函数的调用速度慢,因此尽量少使用系统调用。

 

使用over-eager evaluation方法,其原因我们必须增大数组的尺寸以容纳索引i,那么根据相关性原则上我们就增加数组尺寸以在未来容纳比i大的其他索引:

 

template<class T>
T& DynArray<T>::operator[](int index)
{
	if(index < 0)
		throw an exception;
	
	if(index > 当前最大的索引值)
		int diff = index - 当前最大的索引值;
		调用new分配足够的额外内存,以使得index+diff合法;
	
	返回index位置上的数组元素;
}

这次内次分配内存是数组扩展所需求的两倍:

 

DynArray<double> a; //此时,只有a[0]是合法的数组

a[22] = 3.5;		 //调用new扩展,有效索引是0-44

a[32] = 0;			 //不用调用new扩展

贯穿本条款的一个常见主题:更快的速度需要更多的内存。cache运行结果需要更多的内存,但是一旦需要被缓存的结果时就能减少重新生成的时间。prefetch需要空间放置prefetch的东西,但是它减少了访问它们所需的时间。以空间换时间!

当你必须支持某些操作而不总需要的结果时,lazy evaluation是在这时候使用的用以提高程序的效率技术。当你必须支持某些操作而结果几乎总是被需要或不止一次的需要时,over-eager是这种时候用以提高程序效率的技术。它们所产生的巨大的性能是值得为这方面花费精力的。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值