非常慢的数据处理

时间:2014-09-24 20:37:01

标签: c

考虑以下代码,将记录数据集加载到缓冲区中,并为每条记录创建一个Record对象。记录构成一个或多个列,并且此信息在运行时被发现。但是,在此特定示例中,我已将列数设置为3.

typedef unsigned int uint;

typedef struct
{
        uint *data;

} Record;

Record *createNewRecord (short num_cols);

int main(int argc, char *argv[])
{
        time_t start_time, end_time;
        int num_cols = 3;
        char *relation;
        FILE *stream;
        int offset;

        char *filename = "file.txt";
        stream = fopen(filename, "r");
        fseek(stream, 0, SEEK_END);
        long fsize = ftell(stream);
        fseek(stream, 0, SEEK_SET);

        if(!(relation = (char*) malloc(sizeof(char) * (fsize + 1))))
        printf((char*)"Could not allocate buffer");

        fread(relation, sizeof(char), fsize, stream);
        relation[fsize] = '\0';
        fclose(stream);

        char *start_ptr = relation;
        char *end_ptr = (relation + fsize);

        while (start_ptr < end_ptr)
        {
                Record *new_record = createNewRecord(num_cols);

                for(short i = 0; i < num_cols; i++)
                {
                        sscanf(start_ptr, " %u %n",
                        &(new_record->data[i]), &offset);

                        start_ptr += offset;
                }
}

Record *createNewRecord (short num_cols)
{
        Record *r;

        if(!(r       = (Record *) malloc(sizeof(Record)))    ||
           !(r->data = (uint *) malloc(sizeof(uint) * num_cols)))
        {
                printf(("Failed to create new a record\n");
        }

        return r;
}

此代码效率极低。我的数据集包含大约3100万条记录(约1 GB),此代码每分钟只处理约200条记录。我将数据集加载到缓冲区的原因是因为我稍后会有多个线程处理此缓冲区中的记录,因此我想避免文件访问。此外,我有一个48 GB的RAM,因此内存中的数据集应该不是问题。关于如何加快速度的任何想法?

解决方案:sscanf功能实际上非常缓慢且效率低下。当我切换到strtoul时,工作在不到一分钟的时间内完成。对记录类型记录的约300万个结构只需几秒钟。

2 个答案:

答案 0 :(得分:1)

确信文件中存在潜伏的非数字数据。

int offset;
...
sscanf(start_ptr, " %u %n", &(new_record->data[i]), &offset);
start_ptr += offset;

请注意,如果文件以非数字输入开头,则永远不会设置offset,如果其值为0,则start_ptr += offset;将永远不会增加。

如果文件中稍后存在非数字数据,例如&#34; 3x&#34;,offset将获得1的值,并导致while循环缓慢进行永远不会得到更新的价值。

最好检查fread()ftell()sscanf()的结果是否有意外的返回值,并采取相应的行动。

此外:long fsize可能太小了。期待使用fgetpos()fsetpos()

注意:为节省处理时间,请考虑使用strtoul(),因为它肯定比sscanf(" %u %n")更快。再次 - 检查错误结果。

BTW:如果代码需要才能使用sscanf(),请使用sscanf("%u%n"),速度更快,代码和功能相同。

答案 1 :(得分:0)

我不是优化专家,但我认为一些技巧应该会有所帮助。

首先,我建议您使用filenamenum_cols作为,因为当我看不到您更改其值时,它们往往更快作为文字代码。

Seond,使用结构只存储一个成员通常是not recommended,但如果你想将它与函数一起使用,你应该只传递指针。因为我看到你使用malloc来存储一个结构并再次存储唯一的成员,所以我想这就是它太慢的原因。你使用的内存是你需要的两倍。但是,某些编译器可能不是这种情况。实际上,使用只有一个成员的结构是没有意义的。如果你想确保你得到的整数(在你的情况下)是一个特定的记录,你可以输入它。

您还应为some optimization制作end_pointerfsize const。

现在,就功能而言,请查看memory mapping io