如何有效地用C编写文本文件,文件大小为5GB

如何有效地用C编写文本文件,文件大小为5GB,c,io,C,Io,我使用这些代码来写入txt文件,但是当输出文件非常大(它的大小可能会增长到5GB)时,速度会非常慢,我需要等待很长时间。 谁能告诉我一个更好的方法来写入txt文件 编辑: p是一个const char*变量。我可能需要在电脑上等一个小时。我只是检查txt文件的大小是否增长到了20GB FILE *fp; fp = fopen(pch, "wb"); while(1) fwrite(p, sizeof(char), strlen(p) / sizeof(char), fp); while (!d

我使用这些代码来写入txt文件,但是当输出文件非常大(它的大小可能会增长到5GB)时,速度会非常慢,我需要等待很长时间。 谁能告诉我一个更好的方法来写入txt文件

编辑:
p
是一个
const char*
变量。我可能需要在电脑上等一个小时。我只是检查txt文件的大小是否增长到了20GB

FILE *fp;
fp = fopen(pch, "wb");
while(1)
fwrite(p, sizeof(char), strlen(p) / sizeof(char), fp);
while (!done)    
    {
        const char *p = icmDisassemble(processor[i], currentPC);
        fwrite(p, sizeof(char), strlen(p) / sizeof(char), fp);
        fwrite("\n", sizeof(char), 1, fp);
        done = (icmSimulate(processor[i], 1) != ICM_SR_SCHED);
    }

我已经测试了您的代码的空实现,以了解什么是
fwrite
性能,我相信瓶颈肯定不是
fwrite

FILE *fp;
fp = fopen(pch, "wb");
while(1)
fwrite(p, sizeof(char), strlen(p) / sizeof(char), fp);
while (!done)    
    {
        const char *p = icmDisassemble(processor[i], currentPC);
        fwrite(p, sizeof(char), strlen(p) / sizeof(char), fp);
        fwrite("\n", sizeof(char), 1, fp);
        done = (icmSimulate(processor[i], 1) != ICM_SR_SCHED);
    }
桌面SATA磁盘(非SSD)的写入速度介于50到60 MB/s之间,或每分钟2 Gb。这比
dd
慢大约50%,或者说是相同的数量级:

touch test.dat; ( ./testx & ); for i in $( seq 1 7 ); do \
    date | tr "\n" "\t"; du -sh test.dat; \
    sleep 10; done; \
killall -KILL testx; rm -f test.dat
我的硬件时钟保持在100 MB/s左右,因此90.3 MB/s是一个可信的数字(我现在正在使用该系统,可能会稍微慢一点)

更改字符串长度不会显著更改时间:

time dd if=/dev/zero of=test.dat bs=1M count=5300
5300+0 records in
5300+0 records out
5557452800 bytes (5.6 GB) copied, 61.5375 s, 90.3 MB/s

real    1m2.105s
user    0m0.000s
sys     0m9.544s
那么瓶颈在哪里呢? 我真的没有什么选择

  • 它在磁盘上。尝试在您的计算机上运行我的代码几分钟。它应该能写大约10G的垃圾。显著较低的数字可能表明磁盘设置、文件系统、甚至物理支持或接口硬件中存在错误

  • 这是一个很好的例子。您说它不是,但让我们假设它经常返回一个长度为零的字符串。通过返回“”,我得到了更差的性能:1.5 Gb/分钟,而不是4-5 Gb/分钟

在后一种情况下,您可以尝试计算得到的线长度:

// "D'oh"

Fri Jun 12 19:36:50 CEST 2015   1.5M    test.dat
Fri Jun 12 19:37:00 CEST 2015   751M    test.dat
Fri Jun 12 19:37:10 CEST 2015   1.5G    test.dat
Fri Jun 12 19:37:20 CEST 2015   2.2G    test.dat
Fri Jun 12 19:37:31 CEST 2015   2.9G    test.dat
Fri Jun 12 19:37:41 CEST 2015   3.6G    test.dat
Fri Jun 12 19:37:51 CEST 2015   4.4G    test.dat

// First lengthy sentence of *I Promessi Sposi*

Fri Jun 12 19:39:42 CEST 2015   8.4M    test.dat
Fri Jun 12 19:39:52 CEST 2015   1.2G    test.dat
Fri Jun 12 19:40:02 CEST 2015   2.1G    test.dat
Fri Jun 12 19:40:14 CEST 2015   3.1G    test.dat
Fri Jun 12 19:40:25 CEST 2015   4.0G    test.dat
Fri Jun 12 19:40:35 CEST 2015   4.8G    test.dat
Fri Jun 12 19:40:45 CEST 2015   5.7G    test.dat

// "The rain in Spain"

Fri Jun 12 19:41:21 CEST 2015   7.3M    test.dat
Fri Jun 12 19:41:31 CEST 2015   1.2G    test.dat
Fri Jun 12 19:41:43 CEST 2015   2.1G    test.dat
Fri Jun 12 19:41:53 CEST 2015   3.0G    test.dat
Fri Jun 12 19:42:03 CEST 2015   3.9G    test.dat
Fri Jun 12 19:42:13 CEST 2015   4.6G    test.dat
Fri Jun 12 19:42:23 CEST 2015   5.3G    test.dat
如果您看到大量的零长度线,那么可以这样做:

  10931 ....
   4319 .....
   1680 ......
    629 .......
    288 ........
    142 .........
     54 ..........
     21 ...........
     18 ............
      6 .............
      3 ..............
      4 ...............
      3 ................
      1 .................
另一种可能是尝试使用更大的缓冲区。使用64K缓冲区(应该足够了),即使写入零长度字符串和回车,我也能获得正常的性能:

  const char *p = icmDisassemble(processor[i], currentPC);
  // Ignore zero-length output.
  if (p[0]) {
    fwrite(p, sizeof(char), strlen(p) / sizeof(char), fp);
    fwrite("\n", sizeof(char), 1, fp);
  }
这是修改后的代码(请注意,缓冲区不是以零结尾的-“\n”覆盖了以零结尾的缓冲区)

保存
strlen
调用(将第一个strlen保存到变量中并使用
memcpy
)不会明显改变结果。在我的系统上,两倍大的缓冲区也无法带来任何好处

  • 这是一个很好的例子。请注意,不一定,但有时。可能在非常罕见的情况下,它会发现一些笨拙的数据并阻塞,或者在恢复、重复检查或调用昂贵的函数时损失很长时间。我们怎么进去查这个?你可以给函数计时——给定慢度的数量级,我们只需要能够计算毫秒;有几个片段可以做到这一点

    #define ICM_BUF_LEN 0x10000
    char *buffer = malloc(ICM_BUF_LEN);
    size_t bufptr = 0;
    
    while (!done)
    {
        const char *p = icmDisassemble(processor[i], currentPC);
        if ((strlen(p) + bufptr + 1) >= ICM_BUF_LEN) {
                fwrite(buffer, 1, bufptr, fp);
                bufptr = 0;
        }
        strcpy(buffer + bufptr, p);
        bufptr += strlen(p);
        buffer[bufptr++] = '\n';
        done = (icmSimulate(processor[i], 1) != ICM_SR_SCHED);
    }
    fwrite(buffer, 1, bufptr, fp);
    free(buffer); buffer = NULL;
    
    int倍[1000];
    对于(j=0;j<1000;j++){times[j]=0;}
    而(!完成)
    {
    大小;
    int ms1=gettimemillizes();
    const char*p=ICM反汇编(处理器[i],当前PC);
    int ms2=gettimemillizes()-ms1;
    如果(ms2>999){
    ms2=999;
    }
    次[ms2]++;
    
运行后,或者如果时钟超过了正常运行时间,则将数组转储到stdout,忽略零个条目,并得到如下结果:

int times[1000];
for (j = 0; j < 1000; j++) { times[j] = 0; }

while (!done)
{
    size_t  s;
    int     ms1 = getTimeMilliseconds();
    const char *p = icmDisassemble(processor[i], currentPC);
    int     ms2 = getTimeMilliseconds() - ms1;
    if (ms2 > 999) {
        ms2 = 999;
    }
    times[ms2]++;
次
----

0 182493
需要等待很长时间
=>秒?分钟?小时?SSD?HDD?USB?网络?什么是
p
?请注意
sizeof(char)
是冗余的(定义为1)-因此更改:
fwrite(p,sizeof(char),strlen(p)/sizeof(char),fp);
fwrite(p,1,strlen(p),fp)
哪个平台?您在哪里编写?您的系统使用哪个文件系统?什么是
p
?换句话说,每次调用
fwrite()
要写多少字节?
int times[1000];
for (j = 0; j < 1000; j++) { times[j] = 0; }

while (!done)
{
    size_t  s;
    int     ms1 = getTimeMilliseconds();
    const char *p = icmDisassemble(processor[i], currentPC);
    int     ms2 = getTimeMilliseconds() - ms1;
    if (ms2 > 999) {
        ms2 = 999;
    }
    times[ms2]++;
times
----
0         182493 <-- times obviously not zero, but still < 1 ms
1         9837
2         28
3         5
6         1
135       1 <---- two suspicious glitches (program preempted by kernel?)
337       1 <--
999       5 <-- on five occasions the function has stalled