[转载]循环??负担??

博客围绕循环优化展开,指出循环常是优化最佳位置。介绍了在整型数组查找元素索引值的优化方法,如Knuth提出的guard_search,测试显示优化效果显著。还提及无法使用该算法时,可采用Duff's Device,测试表明能提高约10%的执行效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

循环本身也是一个很大的开销,尤其是当循环体本身的运行速度很快的时候。这里讨论了一些避免额外开销的方式。

循环,不夸张地说,是每个程序员每天都要遇到的。作为结构化编程的三个主要结构之一,循环出现在每一个软件项目的几乎每一个源程序里。当一件事被放入循环的时候,就表明这件事可能会被做很多次,这也使得循环往往是优化的最佳位置。

很少有人想过,循环本身也是一个很大的开销。尤其是当循环体本身的运行速度很快的时候。譬如说,下面这个函数,可能每个人都曾经写过:


int search( const int* pi, int iSize, int iValue )
{
    for ( int i = 0; i < iSize; ++i )
        if ( pi[ i ] == iValue )
            return i;
    return -1;
}


这个函数用来在一个整型数组里查找第一个与给定值相等的整数的索引值。如果我们把这个函数用更直接(对编译器来说)的方法写出来,可能是


int expanded_search( const int* pi, int iSize, int iValue )
{
    int i = 0;
    goto judge;
loop:
    if ( pi[ i ] == iValue )
        return i;
judge:
    ++i;
    if ( i < iSize )
        goto loop;
    return -1;
}


请注意,循环代码本身和循环体几乎消耗了相同的时间。也就是说,如果我们能够避免这种循环方式(循环本身是不可能避免的)的话,我们可以获得几乎100%的速度提升。Ronald E. Knuth在他的巨著The Art of Computer Programming中提到了这样一种方法:


int guard_search( int* pi, int iSize, int iValue )
{
    int* p = pi;
    p[ iSize ] = iValue;
    while ( *p != iValue )
        ++p;
    return p == pi + iSize ? -1 : p - pi;
}


与其它方法相比,唯一的要求是:供搜索的数组最后必须有一个元素是空的。这在实际程序里非常容易实现,尤其是在需要以此来换取执行速度的情况下。从测试结果(如下)可以看到,优化的效果相当显著。

search :380
expanded_search :371
guard_search :190

有的时候,你没有办法实现设定一个守护(guard)变量,或者你无法提供那个最后的空元素。例如下面的这个函数:


void assign( int* piDest, const int* piSrc, int iSize )
{
    for ( int i = 0; i < iSize; ++i )
        *piDest++ = *piSrc++ + 1;
}


在这种情况下,Knuth算法就不能使用了。这时,我们可以使用Duff's Device----由Duff提出了一个算法。修改后的函数如下:


void duff_assign( int* piDest, const int* piSrc, int iSize )
{
    int i;
    switch ( iSize % 4 )
    {
    case 0:
        for ( i = 0; i < iSize / 4; ++i )
        {
            *piDest++ = *piSrc+++1;
    case 1:
            *piDest++ = *piSrc+++1;
    case 2:
            *piDest++ = *piSrc+++1;
    case 3:
            *piDest++ = *piSrc+++1;
        }
    }
}


可以看到,这个函数非常"丑陋",第一眼看上去,甚至怀疑它是否能通过编译。事实上,这是对C/C++语法的一种"特殊"使用方式,其主要目的是,减少在循环里的跳转和判断,以在每次循环执行时循环体获得更多的比重。

测试结果如下:

不使用Duff's Device:10235
使用Duff's Device:9263

提高了大约10%,虽然不多,但是如果能通过这样简单的改动,就可以使核心代码执行效率提高的话,也是很值得的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值