C fprintf / fscanf优化大文件的速度

我合并了两个大的(每个8 GB左右)文件。 我尝试优化它,尽可能好。

void merge() { char *array[17]= {"q.out","b.out"}; // names of input files FILE *finpt1 = fopen(array[0],"r"), *finpt2 = fopen (array[1],"r"), *foutp = fopen("final_.out","w"); u_int32_t a,b; fscanf(finpt1, "%u", &a); fscanf(finpt2, "%u", &b); int EOF1_my = 0, EOF2_my = 0; while (true) { if ( a>b ) { fprintf( foutp,"%u\n", b); if ( fscanf(finpt2, "%u", &b) == EOF) { EOF2_my = EOF; break; } } else { fprintf( foutp,"%u\n", a); if ( fscanf(finpt1, "%u", &a) == EOF) { EOF1_my = EOF; break; } } } if ( EOF1_my == EOF) { while ( fscanf(finpt2, "%u", &a) != EOF) fprintf(foutp, "%u\n", a); } else if ( EOF2_my == EOF) { while (fscanf(finpt1, "%u", &b) != EOF) fprintf( foutp,"%u\n", b); } fclose(finpt1); fclose(finpt2); fclose(foutp); } 

我怀疑多次调用printf消耗了大量资源(我注意到我的日志记录程序比没有日志的情况下工作速度慢得多)。 我认为大多数时候它花费格式化字符串(不写入文件,因为使用了缓冲)。

所以我想知道在自己的内存中编写字符串并输出是否更好,例如10000个符号到一个文件,一个吸引fprintf函数 – 如fprintf(“%s”,string);?

我对fscanf有同样的疑虑。 也许我应该使用其他一些function?

欢迎任何想法。 提前致谢!

固定BUG
感谢sfstewman(在评论中注意到问题)。 很酷,这是非常有价值的信息,我不会注意到,直到我不开始写测试(或可能永远不会)
谢谢你的代码,但无论如何给我准备好代码,你离开我没有乐趣。
这是我的蛋糕!
想法更有价值,现在我知道词典比较是什么)

您的输入都是无符号数字。 这意味着您可以使用字典比较而不是数字比较。

要使字典比较适用于无符号数字的字符串,首先要比较字符串的长度(较短的字符串是较小的数字)。 如果长度相等, strcmp将指示哪个字符串具有较小的数字。

如果使用换行作为数字之间的分隔符,则可以使用fgetsfputs进行读/写,从而消除了fscanffprintf格式化的成本。 这消除了字符串之间的所有转换数字。 fgets返回的字符串末尾的换行符在所有数字中都是不变的,不会影响字典比较。

我生成了两个由换行符分隔的随机无符号数的9.5M文件,并进行了时序比较(merge1是你上面的代码,merge2在下面):

 % time ./merge1 ./merge1 0.89s user 0.08s system 99% cpu 0.974 total % time ./merge2 ./merge2 0.18s user 0.08s system 98% cpu 0.264 total 

并且,在一个更大的测试集上(两个537M的随机数文件,介于0和2 ^ 30-1之间):

 % time ./merge1 ./merge1 51.22s user 4.57s system 54% cpu 1:41.68 total % time ./merge2 ./merge2 11.13s user 4.68s system 18% cpu 1:26.81 total 

这表明数值转换占用了你75%-80%的时间。 如果这还不够快,你可以通过自己的缓冲和使用strchr搜索分隔符,并可能使用内存映射文件来进一步优化它。

 #include  #include  void merge() { char *array[17]= {"q.out","b.out"}; // names of input files FILE *finpt1 = fopen(array[0],"r"), *finpt2 = fopen (array[1],"r"), *foutp = fopen("final_.out","w"); char buf1[32]; char buf2[32]; memset(buf1,0,sizeof(buf1)); memset(buf2,0,sizeof(buf2)); int EOF1_my = (fgets(buf1, sizeof(buf1), finpt1) == NULL); int EOF2_my = (fgets(buf2, sizeof(buf2), finpt2) == NULL); size_t l1 = strlen(buf1); size_t l2 = strlen(buf2); if (!EOF1_my && !EOF2_my) { for(;;) { /* unsigned numbers, so use a lexographic comparison */ int diff = (l1 == l2) ? strcmp(buf1,buf2) : l1-l2; if (diff < 0) { fputs( buf1, foutp ); memset(buf1,0,sizeof(buf1)); EOF1_my = (fgets(buf1, sizeof(buf1), finpt1) == NULL); if (EOF1_my) break; l1 = strlen(buf1); } else { fputs( buf2, foutp ); memset(buf2,0,sizeof(buf2)); EOF2_my = (fgets(buf2, sizeof(buf2), finpt2) == NULL); if (EOF2_my) break; l2 = strlen(buf2); } } } FILE* frest = NULL; if (!EOF1_my || !EOF2_my) { if (!EOF1_my) { fputs(buf1, foutp); frest = finpt1; } else { fputs(buf2, foutp); frest = finpt2; } memset(buf1,0,sizeof(buf1)); while(fgets(buf1,sizeof(buf1),frest) != NULL) { fputs(buf1,foutp); } } fclose(finpt1); fclose(finpt2); fclose(foutp); } int main() { merge(); return 0; }