我将两个大文件(每个大约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”,字符串);?
我对fscanf有同样的疑虑。也许我应该使用其他一些功能?
欢迎任何想法。 提前谢谢!
修复BUG
感谢sfstewman(在评论中注意到问题)。
很酷,这是非常有价值的信息,在我不开始编写测试之前我不会注意到(或者可能永远不会)
谢谢你的代码,但无论如何给我准备好代码,你离开我没有乐趣。
这是我的蛋糕!
想法更有价值,现在我知道词典比较是什么)
答案 0 :(得分:2)
您的输入都是无符号数字。这意味着您可以使用字典比较而不是数字比较。
要使字典比较适用于无符号数字的字符串,首先要比较字符串的长度(较短的字符串是较小的数字)。如果长度相等,strcmp
将指示哪个字符串具有较小的数字。
如果您使用换行符作为数字之间的分隔符,则可以使用fgets
和fputs
进行读/写,从而消除了fscanf
和fprintf
中格式设置的成本。这消除了字符串之间的所有转换数字。 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 <stdio.h>
#include <string.h>
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;
}