5章 优化程序性能

主要探讨如何使用几种不同类型的程序优化技术,使程序运行更加快。

主要结合硬件解释了如何优化,这章不必深入追究,追究也不会明白。
必须写出清晰简洁的代码,这样左不仅为了程序员能够看懂代码,也是为了在检查代码时,别人能够读懂和理解代码。

不依赖于目标机器特性的优化

选择合适的算法和数据结构是前提,然后再进行1、2、3的基本优化。
1、消除循环的低效率

消除循环的条件测试中一些计算结果不会改变的计算。这种很简单的方法称为代码移动。编译器自己也会尽可能代码移动,但是可能调用函数具有副作用那么优化移动失败,这种情况下必须显示地帮助编译器完成代码移动,增加程序性能

2、消除不必要的过程调用

过程调用,创建栈帧会造成不小的开销,所以可以不用过程调用的地方尽量不用过程调用,直接内联即可。

3、消除不必要的存储器引用

引入临时变量(编译器会分配寄存器存储,寄存器访问快速)来存储结果,最后计算结果放回数组或全全局变量或传入地址操作,可以加速程序性能。

int strlen(const char *s)//只需要一个const,表示s不能改变s指向的数值,后面一个const不需要,因为s是形参,是实参的压栈,在这里没必要保护形参
{
    int len;
    while(*s++ != '\0')
        len++;
    return len;
}//大写字母比小写字母数字小32
void lower(char *s)
{
    int i;
    for(i = 0 ; i < strlen(s) ; i++ ){
        if(s[i] >= 'A' && s[i] <= 'Z')
            s[i] += ('a' - 'A');
    }
}

void lower1(char *s)
{
    int i;
    int len = strlen(s);//这句话就是简单的代码移动,对于大字符串,这相当有用,
    //写代码就应该时刻记住这种代码移动,增加性能。时刻记住大数据。
    for(i = 0 ; i < len ; i++ ){
        if(s[i] >= 'A' && s[i] <= 'Z')
            s[i] += ('a' - 'A');
    }
}
#define IDENT 1//向量操作初始值
#define OP  *//乘
typedef struct {
    long int len;
    data_t *data;
}vec_rec, *vec_ptr;

vec_ptr new_vec(long int len)//返回长度为len的向量
{
    vec_ptr result = (vec_ptr) malloc(sizeof(vec_rec));//分配一个结构体头,指向存储向量的一维数组
    if (!result)
        return NULL;  /*  */
    result->len = len;

    result->allocated_len = len;

    if (len > 0) {
        data_t *data = (data_t *)calloc(len, sizeof(data_t));//分配一维数组
    if (!data) {
        free((void *) result);
        return NULL; /*  */
    }
    result->data = data;
    }
    else
    result->data = NULL;
    return result;//返回头指针,头指针和存储向量的地方,全部动态分配.
}

int get_vec_element(vec_ptr v, long int index, data_t *dest)//通过索引获取向量元素
{
    if (index < 0 || index >= v->len)//防止越界
    return 0;
    *dest = v->data[index];
    return 1;
}

long int vec_length(vec_ptr v)
{
    return v->len;
}

data_t *get_vec_start(vec_ptr v)//返回向量首地址
{
    return v->data;
}

void combine1(vec_ptr v, data_t *dest)//最原始操作,没有经过任何软件优化
{
    long int i;

    *dest = IDENT;
    for (i = 0; i < vec_length(v); i++) {
        data_t val;
        get_vec_element(v, i, &val);
        *dest = *dest OP val;
    }
}
void combine2(vec_ptr v, data_t *dest)//消除了循环中的低效率部分,减少了条件判断中函数的调用
{
    long int i;
    long int length = vec_length(v);

    *dest = IDENT;
    for (i = 0; i < length; i++) {
    data_t val;
    get_vec_element(v, i, &val);
    *dest = *dest OP val;
    }
}
void combine3(vec_ptr v, data_t *dest)//消除了循环中的低效率部分,较少了循环内部的过程调用,直接通过数组索引数值
{
    long int i;
    long int length = vec_length(v);
    data_t *data = get_vec_start(v);

    *dest = IDENT;
    for (i = 0; i < length; i++) {
        *dest = *dest OP data[i];
    }
}
void combine4(vec_ptr v, data_t *dest)//消除了循环中不必要的内器读写(dest)。通过分配局部变量acc(此时必定分配在寄存器)。最后仅仅一次写搞定
{
    long int i;
    long int length = vec_length(v);
    data_t *data = get_vec_start(v);
    data_t acc = IDENT;

    for (i = 0; i < length; i++) {
        acc = acc OP data[i];
    }
    *dest = acc;
}

对于上述combine3和combine4,编译器不会自动将combine3优化为combine4,因为由于存储器的别名,将导致二者函数调用计算的结果不一样。

combine3(v , get_vec_start(v));//目的地址是第一个元素
combine4(v , get_vec_start(v));//目的地址是第一个元素
//二者产生结果明显不一样

依赖于目标机器特性的优化

这里主要涉及循环展开(减少循环迭代次数)等,一些操作依赖于处理器体系结构,相对比较复杂,暂时不用考虑。

小结

明白一些程序的优化,更复杂和体系结构有关的暂时先不用考虑。优化的优先原则就是选择好的数据结构和算法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

有时需要偏执狂

请我喝咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值