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);
}