打印性能优化[缓冲区大小角度]
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,同时也避免了频繁刷缓冲区,性能上得以更大提升。
以上是关于打印性能优化[缓冲区大小角度]的主要内容,如果未能解决你的问题,请参考以下文章