打印性能优化[缓冲区大小角度]

Posted BHY_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了打印性能优化[缓冲区大小角度]相关的知识,希望对你有一定的参考价值。

问题背景

https://blog.csdn.net/qq_15947787/article/details/119001748?spm=1001.2014.3001.5501

问题分析角度

针对YY个字段信息,每个字段要打印3列信息,按较大值估计一行50个字节,最多可达 ?K左右。从理论上将,超出缓冲区将会引起多次的write操作。

对于超过缓冲区大小输出分析

打印代码

Tick差

分析

string str = "";

for (int i = 0; i < 5000; i++) {

for (int j = 0; j < 2000; j++) {

str += "1";

}

fout << str << "\\n";

str.clear();

}

小于2K

144714

145785

146577

17:10:43.486858 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 2000}], 2) = 2001 <0.000028>

17:10:43.486967 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 2000}], 2) = 2001 <0.000017>

17:10:43.487065 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 2000}], 2) = 2001 <0.000021>

17:10:43.487170 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 2000}], 2) = 2001 <0.000016>

17:10:43.487266 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 2000}], 2) = 2001 <0.000021>

这里str+=”1”测试为”12”和”1\\n”时性能没有明显差异

string str = "";

for (int i = 0; i < 2000; i++) {

for (int j = 0; j < 5000; j++) {

str += "1";

}

fout << str << "\\n";

str.clear();

}

超4K

139111

136928

138226

17:13:12.839220 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 5000}], 2) = 5001 <0.000018>

17:13:12.839329 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 5000}], 2) = 5001 <0.000018>

17:13:12.839436 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 5000}], 2) = 5001 <0.000018>

17:13:12.839545 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 5000}], 2) = 5001 <0.000016>

17:13:12.839652 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 5000}], 2) = 5001 <0.000021>

string str = "";

for (int i = 0; i < 1000; i++) {

for (int j = 0; j < 10000; j++) {

str += "1";

}

fout << str << "\\n";

str.clear();

}

超8K

131784

137378

131725

17:15:14.229337 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 10000}], 2) = 10001 <0.000028>

17:15:14.229515 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 10000}], 2) = 10001 <0.000035>

17:15:14.229700 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 10000}], 2) = 10001 <0.000021>

17:15:14.229871 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 10000}], 2) = 10001 <0.000021>

17:15:14.230042 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 10000}], 2) = 10001 <0.000025>

使用string拼接,统一输出,调用writev,string直接传地址,大小为10000

string str = "";

for (int i = 0; i < 1000; i++) {

for (int j = 0; j < 10000; j++) {

str += "1";

}

fout << str << endl;

str.clear();

}

133347

135463

135448

17:17:26.164393 writev(3, [{"", 0}, {"11111111111111111111111111111111"..., 10000}], 2) = 10000 <0.000023>

17:17:26.164446 write(3, "\\n", 1)       = 1 <0.000012>

17:17:26.164606 writev(3, [{"", 0}, {"11111111111111111111111111111111"..., 10000}], 2) = 10000 <0.000026>

17:17:26.164662 write(3, "\\n", 1)       = 1 <0.000013>

17:17:26.164822 writev(3, [{"", 0}, {"11111111111111111111111111111111"..., 10000}], 2) = 10000 <0.000022>

17:17:26.164874 write(3, "\\n", 1)       = 1 <0.000012>

string输出时的换行,依然由write完成

for (int i = 0; i < 1000; i++) {

for (int j = 0; j < 10000; j++) {

        fout << "1";

    }

    fout << "\\n";

}

465279

467595

471035

16:00:40.941887 writev(3, [{"11111111111111111111111111111111"..., 8190}, {"1", 1}], 2) = 8191 <0.000021>

16:00:40.942307 writev(3, [{"11111111111111111111111111111111"..., 8190}, {"1", 1}], 2) = 8191 <0.000020>

16:00:40.942727 writev(3, [{"11111111111111111111\\n11111111111"..., 8190}, {"1", 1}], 2) = 8191 <0.000022>

16:00:40.943148 writev(3, [{"11111111111111111111111111111111"..., 8190}, {"1", 1}], 2) = 8191 <0.000023>

16:00:40.943570 writev(3, [{"11111111111111111111111111111111"..., 8190}, {"1", 1}], 2) = 8191 <0.000022>

直接写os,默认缓冲区8k,包括换行在内持续输出

for (int i = 0; i < 1000; i++) {

for (int j = 0; j < 10000; j++) {

        fout << "1";

    }

    fout << endl;

}

467999

467723

468518

17:20:54.810326 writev(3, [{"11111111111111111111111111111111"..., 8190}, {"1", 1}], 2) = 8191 <0.000025>

17:20:54.810462 write(3, "11111111111111111111111111111111"..., 1810) = 1810 <0.000013>

17:20:54.810872 writev(3, [{"11111111111111111111111111111111"..., 8190}, {"1", 1}], 2) = 8191 <0.000022>

17:20:54.811007 write(3, "11111111111111111111111111111111"..., 1810) = 1810 <0.000018>

17:20:54.811423 writev(3, [{"11111111111111111111111111111111"..., 8190}, {"1", 1}], 2) = 8191 <0.000023>

17:20:54.811558 write(3, "11111111111111111111111111111111"..., 1810) = 1810 <0.000012>

直接写os,10000次后写入endl,则前8192次直接写,后1810次write写

for (int i = 0; i < 100000; i++) {

fout << "1" <<endl;

}

156273

157962

155850

17:45:54.054019 write(3, "1\\n", 2)      = 2 <0.000012>

17:45:54.054058 write(3, "1\\n", 2)      = 2 <0.000012>

17:45:54.054098 write(3, "1\\n", 2)      = 2 <0.000012>

17:45:54.054137 write(3, "1\\n", 2)      = 2 <0.000011>

17:45:54.054177 write(3, "1\\n", 2)      = 2 <0.000012>

for (int i = 0; i < 100000; i++) {

fout << "1" << "\\n";

}

14744

14365

14147

17:46:55.646126 writev(3, [{"\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1"..., 8190}, {"\\n", 1}], 2) = 8191 <0.000022>

17:46:55.646544 writev(3, [{"1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n"..., 8190}, {"1", 1}], 2) = 8191 <0.000021>

17:46:55.646960 writev(3, [{"\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1"..., 8190}, {"\\n", 1}], 2) = 8191 <0.000021>

17:46:55.647375 writev(3, [{"1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n"..., 8190}, {"1", 1}], 2) = 8191 <0.000024>

17:46:55.647793 writev(3, [{"\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1"..., 8190}, {"\\n", 1}], 2) = 8191 <0.000021>

for (int i = 0; i < 100000; i++) {

fout << "1\\n";

}

7986

5187

5084

17:43:24.933016 writev(3, [{"1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n"..., 8190}, {"1\\n", 2}], 2) = 8192 <0.000019>

17:43:24.933250 writev(3, [{"1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n"..., 8190}, {"1\\n", 2}], 2) = 8192 <0.000019>

17:43:24.933485 writev(3, [{"1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n"..., 8190}, {"1\\n", 2}], 2) = 8192 <0.000020>

17:43:24.933720 writev(3, [{"1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n"..., 8190}, {"1\\n", 2}], 2) = 8192 <0.000020>

17:43:24.933954 writev(3, [{"1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n"..., 8190}, {"1\\n", 2}], 2) = 8192 <0.000019>

"1\\n"连续的优势

string str = "";

for (int i = 0; i < 100000; i++) {

str += "12";

}

fout << str <<endl;

2770

2582

2535

15:00:55.015926 writev(3, [{"", 0}, {"12121212121212121212121212121212"..., 200000}], 2) = 200000 <0.000322>

15:00:55.016320 write(3, "\\n", 1)       = 1 <0.000016>

15:00:55.018379 writev(3, [{"", 0}, {"12121212121212121212121212121212"..., 200000}], 2) = 200000 <0.000215>

15:00:55.018654 write(3, "\\n", 1)       = 1 <0.000015>

15:00:55.020676 writev(3, [{"", 0}, {"12121212121212121212121212121212"..., 200000}], 2) = 200000 <0.000286>

15:00:55.021025 write(3, "\\n", 1)       = 1 <0.000015>

如果拆成2次str +=x

性能略微降低

string str = "";

for (int i = 0; i < 100000; i++) {

str += "1\\n ";

}

fout << str <<endl;

2477

2550

2445

14:59:43.635929 writev(3, [{"", 0}, {"1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n"..., 200000}], 2) = 200000 <0.000241>

14:59:43.636237 write(3, "\\n", 1)       = 1 <0.000016>

14:59:43.638280 writev(3, [{"", 0}, {"1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n"..., 200000}], 2) = 200000 <0.000275>

14:59:43.638627 write(3, "\\n", 1)       = 1 <0.000016>

14:59:43.640692 writev(3, [{"", 0}, {"1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n1\\n"..., 200000}], 2) = 200000 <0.000219>

14:59:43.640972 write(3, "\\n", 1)       = 1 <0.000015>

\\n和普通字符同等对待

string str = "";

for (int i = 0; i < 500; i++) {

for (int j = 0; j < 20000; j++) {

str += "1";

}

fout << str << "\\n";

str.clear();

}

136666

137532

132687

17:24:03.514167 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 20000}], 2) = 20001 <0.000034>

17:24:03.514473 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 20000}], 2) = 20001 <0.000038>

17:24:03.514784 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 20000}], 2) = 20001 <0.000031>

17:24:03.515089 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 20000}], 2) = 20001 <0.000034>

17:24:03.515395 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 20000}], 2) = 20001 <0.000032>

string str = "";

for (int i = 0; i < 50; i++) {

for (int j = 0; j < 200000; j++) {

str += "1";

}

fout << str << "\\n";

str.clear();

}

134238

138384

134882

17:26:17.040128 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 200000}], 2) = 200001 <0.000287>

17:26:17.043042 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 200000}], 2) = 200001 <0.000210>

17:26:17.045880 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 200000}], 2) = 200001 <0.000197>

17:26:17.048703 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 200000}], 2) = 200001 <0.000202>

17:26:17.051510 writev(3, [{"\\n", 1}, {"11111111111111111111111111111111"..., 200000}], 2) = 200001 <0.000195>

用string做字符串拼接,最后一次写入的方式中,总写入量一定,耗费的时间差异不大。

每次都fout输出方式,达到刷缓冲区条件的方式中,性能并不理想。

os多次打印输出时,"\\n"结合到前面字符串中,可提升一倍效率。

反汇编对比

打印代码

int main()

{

    std::ofstream fout("1.txt");

    for (int j = 0; j < 10000; j++) {

      fout << "1" << endl;

    }

    fout.close();

    return 0;

}

0000000000400a78 <main>:

  400a78:       55                      push   %rbp

  400a79:       48 89 e5                mov    %rsp,%rbp

  400a7c:       53                      push   %rbx

  400a7d:       48 81 ec 18 02 00 00    sub    $0x218,%rsp

  400a84:       be 20 00 00 00          mov    $0x20,%esi

  400a89:       bf 10 00 00 00          mov    $0x10,%edi

  400a8e:       e8 ee 00 00 00          callq  400b81 <_ZStorSt13_ios_OpenmodeS_>

  400a93:       89 c2                   mov    %eax,%edx

  400a95:       48 8d 85 e0 fd ff ff    lea    -0x220(%rbp),%rax

  400a9c:       be 55 0c 40 00          mov    $0x400c55,%esi

  400aa1:       48 89 c7                mov    %rax,%rdi

  400aa4:       e8 97 fe ff ff          callq  400940 <_ZNSt14basic_ofstreamIcSt11char_traitsIcEEC1EPKcSt13_Ios_Openmode@plt>

  400aa9:       c7 45 ec 00 00 00 00    movl   $0x0,-0x14(%rbp)

  400ab0:       81 7d ec 0f 27 00 00    cmpl   $0x270f,-0x14(%rbp)

  400ab7:       7f 27                   jg     400ae0 <main+0x68>

  400ab9:       48 8d 85 e0 fd ff ff    lea    -0x220(%rbp),%rax

  400ac0:       be 5b 0c 40 00          mov    $0x400c5b,%esi

  400ac5:       48 89 c7                mov    %rax,%rdi

  400ac8:       e8 33 fe ff ff          callq  400900 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>

  400acd:       be 50 09 40 00          mov    $0x400950,%esi

  400ad2:       48 89 c7                mov    %rax,%rdi

  400ad5:       e8 56 fe ff ff          callq  400930 <_ZNSolsEPFRSoS_E@plt> // endl输出

  400ada:       83 45 ec 01             addl   $0x1,-0x14(%rbp)

  400ade:       eb d0                   jmp    400ab0 <main+0x38> //0xab0位置

  400ae0:       48 8d 85 e0 fd ff ff    lea    -0x220(%rbp),%rax

  400ae7:       48 89 c7                mov    %rax,%rdi

  400aea:       e8 31 fe ff ff          callq  400920 <_ZNSt14basic_ofstreamIcSt11char_traitsIcEE5closeEv@plt>

  400aef:       bb 00 00 00 00          mov    $0x0,%ebx

  400af4:       48 8d 85 e0 fd ff ff    lea    -0x220(%rbp),%rax

  400afb:       48 89 c7                mov    %rax,%rdi

  400afe:       e8 0d fe ff ff          callq  400910 <_ZNSt14basic_ofstreamIcSt11char_traitsIcEED1Ev@plt>

  400b03:       89 d8                   mov    %ebx,%eax

  400b05:       eb 1d                   jmp    400b24 <main+0xac>

  400b07:       48 89 c3                mov    %rax,%rbx

  400b0a:       48 8d 85 e0 fd ff ff    lea    -0x220(%rbp),%rax

  400b11:       48 89 c7                mov    %rax,%rdi

  400b14:       e8 f7 fd ff ff          callq  400910 <_ZNSt14basic_ofstreamIcSt11char_traitsIcEED1Ev@plt>

  400b19:       48 89 d8                mov    %rbx,%rax

  400b1c:       48 89 c7                mov    %rax,%rdi

  400b1f:       e8 4c fe ff ff          callq  400970 <_Unwind_Resume@plt>

  400b24:       48 81 c4 18 02 00 00    add    $0x218,%rsp

  400b2b:       5b                      pop    %rbx

  400b2c:       5d                      pop    %rbp

  400b2d:       c3                      retq

int main()

{

    std::ofstream fout("1.txt");

    for (int j = 0; j < 10000; j++) {

      fout << "1" << "\\n";

    }

    fout.close();

    return 0;

}

0000000000400998 <main>:

  400998:       55                      push   %rbp

  400999:       48 89 e5                mov    %rsp,%rbp

  40099c:       53                      push   %rbx

  40099d:       48 81 ec 18 02 00 00    sub    $0x218,%rsp

  4009a4:       be 20 00 00 00          mov    $0x20,%esi

  4009a9:       bf 10 00 00 00          mov    $0x10,%edi

  4009ae:       e8 ee 00 00 00          callq  400aa1 <_ZStorSt13_Ios_OpenmodeS_>

  4009b3:       89 c2                   mov    %eax,%edx

  4009b5:       48 8d 85 e0 fd ff ff    lea    -0x220(%rbp),%rax

  4009bc:       be 75 0b 40 00          mov    $0x400b75,%esi

  4009c1:       48 89 c7                mov    %rax,%rdi

  4009c4:       e8 a7 fe ff ff          callq  400870 <_ZNSt14basic_ofstreamIcSt11char_traitsIcEEC1EPKcSt13_Ios_Openmode@plt>

  4009c9:       c7 45 ec 00 00 00 00    movl   $0x0,-0x14(%rbp)

  4009d0:       81 7d ec 0f 27 00 00    cmpl   $0x270f,-0x14(%rbp)

  4009d7:       7f 27                   jg     400a00 <main+0x68>

  4009d9:       48 8d 85 e0 fd ff ff    lea    -0x220(%rbp),%rax

  4009e0:       be 7b 0b 40 00          mov    $0x400b7b,%esi

  4009e5:       48 89 c7                mov    %rax,%rdi

  4009e8:       e8 53 fe ff ff          callq  400840 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>  前面单独的<<”1”

  4009ed:       be 7d 0b 40 00          mov    $0x400b7d,%esi

  4009f2:       48 89 c7                mov    %rax,%rdi

  4009f5:       e8 46 fe ff ff          callq  400840 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt> 后面单独的<<”\\n”

  4009fa:       83 45 ec 01             addl   $0x1,-0x14(%rbp)

  4009fe:       eb d0                   jmp    4009d0 <main+0x38>

  400a00:       48 8d 85 e0 fd ff ff    lea    -0x220(%rbp),%rax

  400a07:       48 89 c7                mov    %rax,%rdi

  400a0a:       e8 51 fe ff ff          callq  400860 <_ZNSt14basic_ofstreamIcSt11char_traitsIcEE5closeEv@plt>

  400a0f:       bb 00 00 00 00          mov    $0x0,%ebx

  400a14:       48 8d 85 e0 fd ff ff    lea    -0x220(%rbp),%rax

  400a1b:       48 89 c7                mov    %rax,%rdi

  400a1e:       e8 2d fe ff ff          callq  400850 <_ZNSt14basic_ofstreamIcSt11char_traitsIcEED1Ev@plt>

  400a23:       89 d8                   mov    %ebx,%eax

  400a25:       eb 1d                   jmp    400a44 <main+0xac>

  400a27:       48 89 c3                mov    %rax,%rbx

  400a2a:       48 8d 85 e0 fd ff ff    lea    -0x220(%rbp),%rax

  400a31:       48 89 c7                mov    %rax,%rdi

  400a34:       e8 17 fe ff ff          callq  400850 <_ZNSt14basic_ofstreamIcSt11char_traitsIcEED1Ev@plt>

  400a39:       48 89 d8                mov    %rbx,%rax

  400a3c:       48 89 c7                mov    %rax,%rdi

  400a3f:       e8 4c fe ff ff          callq  400890 <_Unwind_Resume@plt>

  400a44:       48 81 c4 18 02 00 00    add    $0x218,%rsp

  400a4b:       5b                      pop    %rbx

  400a4c:       5d                      pop    %rbp

  400a4d:       c3                      retq

int main()

{

    std::ofstream fout("1.txt");

    for (int j = 0; j < 10000; j++) {

      fout << "1\\n";

    }

    fout.close();

    return 0;

}

0000000000400998 <main>:

  400998:       55                      push   %rbp

  400999:       48 89 e5                mov    %rsp,%rbp

  40099c:       53                      push   %rbx

  40099d:       48 81 ec 18 02 00 00    sub    $0x218,%rsp

  4009a4:       be 20 00 00 00          mov    $0x20,%esi

  4009a9:       bf 10 00 00 00          mov    $0x10,%edi

  4009ae:       e8 e1 00 00 00          callq  400a94 <_ZStorSt13_Ios_OpenmodeS_>

  4009b3:       89 c2                   mov    %eax,%edx

  4009b5:       48 8d 85 e0 fd ff ff    lea    -0x220(%rbp),%rax

  4009bc:       be 65 0b 40 00          mov    $0x400b65,%esi

  4009c1:       48 89 c7                mov    %rax,%rdi

  4009c4:       e8 a7 fe ff ff          callq  400870 <_ZNSt14basic_ofstreamIcSt11char_traitsIcEEC1EPKcSt13_Ios_Openmode@plt>

  4009c9:       c7 45 ec 00 00 00 00    movl   $0x0,-0x14(%rbp)

  4009d0:       81 7d ec 0f 27 00 00    cmpl   $0x270f,-0x14(%rbp)

  4009d7:       7f 1a                   jg     4009f3 <main+0x5b>

  4009d9:       48 8d 85 e0 fd ff ff    lea    -0x220(%rbp),%rax

  4009e0:       be 6b 0b 40 00          mov    $0x400b6b,%esi

  4009e5:       48 89 c7                mov    %rax,%rdi

  4009e8:       e8 53 fe ff ff          callq  400840 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>  <<”1\\n”输出

  4009ed:       83 45 ec 01             addl   $0x1,-0x14(%rbp)

  4009f1:       eb dd                   jmp    4009d0 <main+0x38>

  4009f3:       48 8d 85 e0 fd ff ff    lea    -0x220(%rbp),%rax

  4009fa:       48 89 c7                mov    %rax,%rdi

  4009fd:       e8 5e fe ff ff          callq  400860 <_ZNSt14basic_ofstreamIcSt11char_traitsIcEE5closeEv@plt>

  400a02:       bb 00 00 00 00          mov    $0x0,%ebx

  400a07:       48 8d 85 e0 fd ff ff    lea    -0x220(%rbp),%rax

  400a0e:       48 89 c7                mov    %rax,%rdi

  400a11:       e8 3a fe ff ff          callq  400850 <_ZNSt14basic_ofstreamIcSt11char_traitsIcEED1Ev@plt>

  400a16:       89 d8                   mov    %ebx,%eax

  400a18:       eb 1d                   jmp    400a37 <main+0x9f>

  400a1a:       48 89 c3                mov    %rax,%rbx

  400a1d:       48 8d 85 e0 fd ff ff    lea    -0x220(%rbp),%rax

  400a24:       48 89 c7                mov    %rax,%rdi

  400a27:       e8 24 fe ff ff          callq  400850 <_ZNSt14basic_ofstreamIcSt11char_traitsIcEED1Ev@plt>

  400a2c:       48 89 d8                mov    %rbx,%rax

  400a2f:       48 89 c7                mov    %rax,%rdi

  400a32:       e8 59 fe ff ff          callq  400890 <_Unwind_Resume@plt>

  400a37:       48 81 c4 18 02 00 00    add    $0x218,%rsp

  400a3e:       5b                      pop    %rbx

  400a3f:       5d                      pop    %rbp

  400a40:       c3                      retq

string s = "";

int main()

{

    std::ofstream fout("1.txt");

    for (int j = 0; j < 10000; j++) {

      s += "1\\n";

    }

    fout << s << endl;

    fout.close();

    return 0;

}

0000000000400d38 <main>:

  400d38:       55                      push   %rbp

  400d39:       48 89 e5                mov    %rsp,%rbp

  400d3c:       53                      push   %rbx

  400d3d:       48 81 ec 18 02 00 00    sub    $0x218,%rsp

  400d44:       be 20 00 00 00          mov    $0x20,%esi

  400d49:       bf 10 00 00 00          mov    $0x10,%edi

  400d4e:       e8 64 01 00 00          callq  400eb7 <_ZStorSt13_Ios_OpenmodeS_>

  400d53:       89 c2                   mov    %eax,%edx

  400d55:       48 8d 85 e0 fd ff ff    lea    -0x220(%rbp),%rax

  400d5c:       be 85 0f 40 00          mov    $0x400f85,%esi

  400d61:       48 89 c7                mov    %rax,%rdi

  400d64:       e8 67 fe ff ff          callq  400bd0 <_ZNSt14basic_ofstreamIcSt11char_traitsIcEEC1EPKcSt13_Ios_Openmode@plt>

  400d69:       c7 45 ec 00 00 00 00    movl   $0x0,-0x14(%rbp)

  400d70:       81 7d ec 0f 27 00 00    cmpl   $0x270f,-0x14(%rbp) // 循环10000次

  400d77:       7f 15                   jg     400d8e <main+0x56>

  400d79:       be 8b 0f 40 00          mov    $0x400f8b,%esi

  400d7e:       bf e0 20 60 00          mov    $0x6020e0,%edi

  400d83:       e8 d8 fd ff ff          callq  400b60 <_ZNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEpLEPKc@plt>

// 调用的是std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::operator+=(char const*)

  400d88:       83 45 ec 01             addl   $0x1,-0x14(%rbp)

  400d8c:       eb e2                   jmp    400d70 <main+0x38> // 目标0xd70,循环体处

  400d8e:       48 8d 85 e0 fd ff ff    lea    -0x220(%rbp),%rax

  400d95:       be e0 20 60 00          mov    $0x6020e0,%esi

  400d9a:       48 89 c7                mov    %rax,%rdi

  400d9d:       e8 7e fe ff ff          callq  400c20 <_ZStlsIcSt11char_traitsIcESaIcEERSt13basic_ostreamIT_T0_ES7_RKNSt7__cxx1112basic_stringIS4_S5_T1_EE@plt>

  400da2:       be e0 0b 40 00          mov    $0x400be0,%esi

  400da7:       48 89 c7                mov    %rax,%rdi

  400daa:       e8 11 fe ff ff          callq  400bc0 <_ZNSolsEPFRSoS_E@plt>

  400daf:       48 8d 85 e0 fd ff ff    lea    -0x220(%rbp),%rax

  400db6:       48 89 c7                mov    %rax,%rdi

  400db9:       e8 e2 fd ff ff          callq  400ba0 <_ZNSt14basic_ofstreamIcSt11char_traitsIcEE5closeEv@plt>

  400dbe:       bb 00 00 00 00          mov    $0x0,%ebx

  400dc3:       48 8d 85 e0 fd ff ff    lea    -0x220(%rbp),%rax

  400dca:       48 89 c7                mov    %rax,%rdi

  400dcd:       e8 be fd ff ff          callq  400b90 <_ZNSt14basic_ofstreamIcSt11char_traitsIcEED1Ev@plt>

  400dd2:       89 d8                   mov    %ebx,%eax

  400dd4:       eb 1d                   jmp    400df3 <main+0xbb>

  400dd6:       48 89 c3                mov    %rax,%rbx

  400dd9:       48 8d 85 e0 fd ff ff    lea    -0x220(%rbp),%rax

  400de0:       48 89 c7                mov    %rax,%rdi

  400de3:       e8 a8 fd ff ff          callq  400b90 <_ZNSt14basic_ofstreamIcSt11char_traitsIcEED1Ev@plt>

  400de8:       48 89 d8                mov    %rbx,%rax

  400deb:       48 89 c7                mov    %rax,%rdi

  400dee:       e8 3d fe ff ff          callq  400c30 <_Unwind_Resume@plt>

  400df3:       48 81 c4 18 02 00 00    add    $0x218,%rsp

  400dfa:       5b                      pop    %rbx

  400dfb:       5d                      pop    %rbp

  400dfc:       c3                      retq

// fout << "1" << endl;

b00495022@linux-x001:~/test> c++filt _ZNSolsEPFRSoS_E

std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))

// fout << "1" << "\\n";

b00495022@linux-x001:~/test> c++filt _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc

std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)

可以看出"1\\n"少次一次call,endl和“\\n”call的函数不同。

优化代码

void functest(std::ostream &os)

{

         std::string str = “”;

         str += "xxxxx\\n";

         while(flag) {

                   str += "[";

                   str += "xxxyyy\\n";

                   str += "zzz";

                   str += "]\\n";

         }

         os << str << endl; // 最后确保函数走完输出到文件或者由调用者flush或者触发自动刷缓冲区条件

}

对于函数中打印少量内容,但换行较多,不想多增加string变量,则推荐 <<”\\n”方式。

其实将string累计字符串时,就不再涉及endl了,每次<<都会做一次call,而string方式则只做一次call,同时也避免了频繁刷缓冲区,性能上得以更大提升。

以上是关于打印性能优化[缓冲区大小角度]的主要内容,如果未能解决你的问题,请参考以下文章

打印性能优化[缓冲区大小角度]

打印性能优化[缓冲区大小角度]

打印性能优化[缓冲区大小角度]

打印性能优化[缓冲模式角度]

打印性能优化[缓冲模式角度]

打印性能优化[缓冲模式角度]