C 随着时间的推移,顺序加载文件的速度会慢得多

C 随着时间的推移,顺序加载文件的速度会慢得多,c,file,fopen,fread,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)

我有以下代码,可以一个接一个地读取和处理多个非常大的文件

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);
}
用于(j=0;j
每个文件包含24000000条推文,我总共读了8个文件,一个接一个。 每行(1条tweet)都会被处理,writeWebet()会在一个非常大的字符数组中复制一个修改过的行

正如你所看到的,我测量时间,看看阅读和处理100万条推文需要多长时间。对于第一个文件,它大约是每100万0.5秒,这已经足够快了。但是每增加一个文件,它就需要越来越长的时间。文件2每一百万行大约需要1秒(但不是每次,只是一些迭代),在文件8上最多需要8秒。这是意料之中的事吗?我能加快速度吗?所有文件或多或少都是完全相同的,总是有2400万行

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

如所愿,WriteWebet()的内容

void writeTweet(char*tweet、const int fn、const int ln、const int hits、const int month、const int day、char*line){
short*ptr1=(short*)推特;
*ptr1=(短)fn;
int*ptr2=(int*)(tweet+2);
*ptr2=ln;
*(tweet+6)=(char)点击次数;
*(推特+7)=(字符)个月;
*(推特+8)=(字符)天;
int i;
int n=TSIZE-9;
对于(i=strlen(行);i
可能,
WriteWebet()
是一个瓶颈。如果将所有处理过的tweet复制到内存中,操作系统必须使用的巨大数据阵列将随着时间的推移而形成。若您并没有足够的内存,或者系统中的其他进程正在积极使用它,操作系统将(在大多数情况下)在磁盘上转储部分数据。它增加了访问阵列的时间。操作系统中存在一种更隐蔽的机制,可以影响性能

您不应该将所有处理过的行存储在内存中。最简单的方法是:将处理过的tweet转储到磁盘上(写入文件)。然而,解决方案取决于您如何进一步使用处理后的tweet。如果不按顺序使用数组中的数据,则值得考虑使用特殊的数据结构来存储(?)。已经有很多库用于此目的——最好查找它们

UPD:

现代OSs()的使用。为了在内核中维护这个模型,有一个特殊的内存管理器,它创建对的特殊引用结构。通常是映射,对于大内存卷,它们引用子映射——这是一个相当大的分支结构。 在使用大块内存时,有必要对内存中的任何页面进行寻址,通常是随机的。对于地址加速,操作系统使用一个特殊的缓存。我不知道这个过程的所有细节,但我认为在这种情况下,缓存应该经常失效,因为没有内存来同时存储所有引用。昂贵的操作会导致性能降低。这将是比内存使用更多


如果您需要对大型tweets数组进行排序,则不必将所有内容都存储在内存中。有很多方法可以解决这个问题。如果要对内存中的数据进行排序,则无需对数组元素执行真正的交换操作。最好使用中间结构来引用tweets数组中的元素,并对引用进行排序,而不是数据。

您能显示
writeweet()的代码吗?
?当然,在主要问题中对其进行了编辑。您实际有多少内存可用?有交换吗?(什么是TWEETS/它是如何分配的?)应该有足够的内存。没有使用交换空间(htop说),我们从8个可用空间中分配大约6GB。如果我只使用2个文件(分配了1500MB),也会发生同样的情况。一个文件需要11秒,两个文件不需要22秒,但大约需要30秒。TWEETS在一个大的malloc()调用中分配。htop说,不使用交换。所需的全部内存通过单个malloc预先分配。我无法将其写入磁盘,因为它是大型快速排序程序的一部分,排序>1亿条推文(这是我们大学课程“并行系统”所需的任务,代码主要来自教授)Ubuntu 13.04(我们使用大学提供的计算机)如果您因为32位/64位问题而询问:它的64位和长度是8字节,所以应该是正确的。@PatrickBauer我更新了答案。也许,它将帮助您处理这个微妙的虚拟内存问题。
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);
}