最新消息:

别一味的迷恋C的性能

c admin 2980浏览 0评论

最近写了一个C程序统计计算web log中的ip每个IP出现的次数,于是采用数据结构中的二叉树进行实现,具体代码如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>

struct tnode {
    char *word;
    int count;
    struct tnode *left;
    struct tnode *right;
};
/* 记录时间 */
static double mytime(void)
{
    struct timeval tv;
    if(gettimeofday(&tv, NULL) == -1) return 0.0;
    return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
}

/* 构建二叉树 */
static struct tnode *addtree(struct tnode *p, char *w)
{
    int cond;
    /* 判断是否为空 如果为空树,构建根节点 */
    if (p == NULL) {
        p = (struct tnode *) malloc(sizeof(struct tnode));
        if (p == NULL) {
            fprintf(stderr, "Cannot alloc memory!");
            exit(-1);
        }
        p->word = strdup(w);
        p->count = 1;
        p->left = p->right = NULL;
    } else if ((cond = strcmp(w, p->word)) == 0)  /* 是否存在叶子节点中*/
        p->count++;                                          /* 如果存在叶子节点计数加一  */
    else if (cond < 0)
        p->left = addtree(p->left, w);                  /* 如果不存在叶子节点且比叶子节点少,则添加左叶子节点 */
    else
        p->right = addtree(p->right, w);              /* 如果存在叶子节点且比叶子节点大,则添加右叶子节点 */

    return p;
}

/* 打印二叉树 */
static void print(struct tnode *p)
{
    if (p != NULL) {
        print(p->left);
        fprintf(stdout, "%s:t%dn", p->word, p->count);
        print(p->right);
    }
}

int main(int argc, char *argv[])
{
    FILE    *fp;
    char    ip[32] = {}, buf[512] = {};
    int     i;
    struct  tnode *root = NULL;

    /* 打开log文件 */
    fp = fopen("access.log", "rb");
    if (fp == NULL) {
        fprintf(stderr, "Cannot open file login.log");
        exit(-1);
    }

    /* 记录当前的时间 */
    double stime = mytime();
    /* 按行读取文件 */
    while (fgets(buf, sizeof(buf), fp)) {
        /* 遇到空格跳出 */
        for (i = 0; i < 16 && buf[i] != ''; i++){
            if (isspace(buf[i])) {
                break;
            }
            ip[i] = buf[i];
        }
        ip[i + 1] = '';
        /* 构建二叉树 */
        root = addtree(root, ip);
    }
    double etime = mytime();
    fclose(fp);                     /* 关闭文件 */
//    print(root);
    fprintf(stdout, "count time:%fn", etime - stime);

    return 0;
}

编译,执行,输出结果

$gcc -o count count.c
$./count
count time:15.735596

附该文本文件大约6607463行 589M大小
同时采用shell脚本

$time awk  '{++S[$1]}END{for (a in S) print > /dev/null }' access.log
real    0m9.757s
user    0m9.069s
sys 0m0.687s

看快了不是一点点,怀疑写的代码中的malloc申请速度过慢,于是采用google的TCMalloc库重新编译和执行

$gcc -o counttc  count.c -ltcmalloc
$./counttc
count time:16.197716

速度就更慢了。
从上面来看,C并不shell快,而且开发调试的时间要远远大于shell的开发调试的时间,而且实现起来也比较的麻烦,该代码的如果要优化的话,可以采用内存池,避免频繁的内存申请,而且可以采用另外的方法进行文件的读取,一次读取一大块文件进行分析,当然工作量更大了。当然很多地方C程序开发出来的性能当然的高,但别总是一味的说C的性能就一定高,关键看是否值得用C去实现,说白了就是根据你的需求办事。

转载请注明:爱开源 » 别一味的迷恋C的性能

您必须 登录 才能发表评论!