顺序,随后的文件加载会随着时间的推移而变慢

时间:2014-07-25 09:22:56

标签: c file fopen fread

我已经获得了以下代码来一个接一个地读取和处理多个非常大的文件。

for(j = 0; j < CORES; ++j) {
    double time = omp_get_wtime();
    printf("File: %d, time: %f\n", j, time);

    char in[256];
    sprintf(in, "%s.%d", FIN, j);

    FILE* f = fopen(in, "r");
    if (f == NULL)
        fprintf(stderr, "open failed: %s\n", FIN);
    int i;
    char buffer[1024];
    char* tweet;
    int takeTime = 1;
    for (i = 0, tweet = TWEETS + (size_t)j*(size_t)TNUM*(size_t)TSIZE; i < TNUM; i++, tweet += TSIZE) {
        double start;
        double end;
        if(takeTime) {
            start = omp_get_wtime();
            takeTime = 0;
        }
        char* line = fgets(buffer, 1024, f);
        if (line == NULL) {
            fprintf(stderr, "error reading line %d\n", i);
            exit(2);
        }
        int fn = readNumber(&line);
        int ln = readNumber(&line);
        int month = readMonth(&line);
        int day = readNumber(&line);
        int hits = countHits(line, key);
        writeTweet(tweet, fn, ln, hits, month, day, line);

        if(i%1000000 == 0) {
            end = omp_get_wtime();
            printf("Line: %d, Time: %f\n", i, end-start);
            takeTime = 1;
        }
    }
    fclose(f);
}

每个文件包含24000000条推文,我总共读了8个文件,一个接一个。 每行(1条推文)都被处理,writeTweet()在一个非常大的char数组中复制一条修改过的行。

正如您所看到的,我衡量时间,看看阅读和处理100万条推文需要多长时间。对于第一个文件,它每百万约0.5秒,这足够快。但是在每个附加文件之后,它需要更长时间。文件2每100万行大约需要1秒(但不是每次都是,只是一些迭代),文件号8最多8秒。这是预期的吗?我可以加快速度吗?所有文件或多或少完全相同,总是有2400万行。

编辑: 附加信息:每个文件需要以处理的形式大约730MB RAM。这意味着,使用8个文件,我们最终需要大约6GB的内存。

如所愿,writeTweet()的内容

void writeTweet(char* tweet, const int fn, const int ln, const int hits, const int month, const int day, char* line) {
    short* ptr1 = (short*) tweet;
    *ptr1 = (short) fn;
    int* ptr2 = (int*) (tweet + 2);
    *ptr2 = ln;
    *(tweet + 6) = (char) hits;
    *(tweet + 7) = (char) month;
    *(tweet + 8) = (char) day;

    int i;
    int n = TSIZE - 9;

    for (i = strlen(line); i < n; i++)
        line[i] = ' '; // padding

    memcpy(tweet + 9, line, n);
}

1 个答案:

答案 0 :(得分:2)

可能writeTweet()是瓶颈。如果您将所有已处理的推文复制到内存中,那么随着时间的推移会形成操作系统必须执行某些操作的巨大数据阵列。如果您没有足够的内存或系统中的其他进程主动使用它,操作系统将转储(在大多数情况下)磁盘上的部分数据。它增加了访问阵列的时间。操作系统中存在更隐蔽的用户眼机制,这会影响性能。

您不应将所有已处理的行存储在内存中。最简单的方法:将已处理的推文转储到磁盘上(写入文件)。但是,解决方案取决于您如何进一步使用已处理的推文。如果不按顺序使用数组中的数据,则值得考虑存储的特殊数据结构(B-trees?)。已经有很多图书馆用于此目的 - 更好地寻找它们。

<强> UPD:

现代操作系统(Linux including)使用virtual memory model。为了在内核中维护此模型,有一个特殊的内存管理器,它创建了对real pages in memory的引用的特殊结构。通常它的地图,对于大型内存卷,它们引用子图 - 它是相当大的分支结构。 在使用大块内存时,有必要经常随机地寻址到任何内存页面。对于地址加速,OS使用特殊缓存。我不知道这个过程的所有细微之处,但我认为在这种情况下,缓存应该经常无效,因为没有内存可以同时存储所有引用。昂贵的操作带来性能降低。这将是更多,而不是使用更多的内存。

如果您需要对大型推文数组进行排序,那么将所有内容存储在内存中并不是必须的。有sorting data on a disk的方法。如果要对内存中的数据进行排序,则无需对数组元素执行实际的交换操作。最好使用带有tweets数组元素引用的中间结构,并对引用而不是数据进行排序。