<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          C++性能真的不如C嗎?

          共 7068字,需瀏覽 15分鐘

           ·

          2022-06-20 11:16


          你好,我是雨樂!

          最近在知乎上看了篇帖子,題目是為什么C++沒有C語言快,如下圖:

          恰好之前研究過這塊,所以借助本文,分析下這個(gè)問題(無意于語言之爭(zhēng),單純是從技術(shù)角度??)。

          眾所周知,C++兼容了C的所有功能,顯然從所有角度去對(duì)比分析是不現(xiàn)實(shí)的,所以本文從我們常用的輸入輸出即標(biāo)準(zhǔn)流(iostream和stdio)的角度來分析講解。

          示例

          為了更加直觀地來對(duì)比分析,寫了個(gè)示例,通過scanf和cin讀文件,然后分析兩種方式的性能高低,代碼如下:

          #include <chrono>
          #include <functional>
          #include <iostream>
          #include <fstream>
          const int num=1000000;

          void time_report(const std::function<void()> &f1, const std::function<void()> &f2) {
             auto start = std::chrono::high_resolution_clock::now();
             f1();
             auto end = std::chrono::high_resolution_clock::now();
             std::cout << "cin cost " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms" << std::endl;

             start = std::chrono::high_resolution_clock::now();
             f2();
             end = std::chrono::high_resolution_clock::now();
             std::cout << "scanf cost " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms" << std::endl;
          }


          void write() {
            std::ofstream file("./data");
            for(int i = 0; i < num; ++i) {
              file << rand() <<' ';
              if((i + 1) % 20 == 0) {
                file << std::endl;
              }
            }
          }
          int main() {
            write(); 
            
            time_report([](){
            freopen("./data","r",stdin);
            int n = 0;
            for(int i=0; i<num; i++) {
                std::cin >> n;
            }
          }, [](){
            freopen("./data","r",stdin);
            int n = 0;
            for(int i = 0; i < num; ++i) {
               scanf("%d", &n);
            }
          });

          return 0;
          }

          編譯,運(yùn)行之后,輸出如下:

          cin cost 686ms
          scanf cost 189ms

          從上述輸出來看,cin的耗時(shí)是scanf的3倍多,果真如此么?

          sync_with_stdio

          C++性能真的差C這么多嗎?直接顛覆了對(duì)C++的認(rèn)知,即使性能真的低,也得知道為什么低吧,于是開始研究,發(fā)現(xiàn)C++為了兼容C,在C標(biāo)準(zhǔn)流(stdio)和C++標(biāo)準(zhǔn)流(iostrem)保持同步,這樣就可以混合使用C和C++風(fēng)格的I/O,且能保證得到合理和預(yù)期的結(jié)果,而正是這個(gè)同步導(dǎo)致C++在cin性能上有損失。如果禁用同步,則允許C++流擁有自己的獨(dú)立緩沖區(qū),這樣性能就會(huì)提升很多。

          那么是否可以禁用該同步功能呢?

          C++提供了一個(gè)函數(shù)std::ios::sync_with_stdio,聲明如下:

          static bool sync_with_stdio(bool __sync = true);

          如果參數(shù)為false,則代表禁用此同步。從上面聲明可以看出,默認(rèn)情況下 __sync = true也就是說禁用同步,而如果__sync為false的話,則會(huì)有如下操作:

          bool
            ios_base::sync_with_stdio(bool __sync) {
              bool __ret = ios_base::Init::_S_synced_with_stdio;
              
              if (!__sync && __ret) {
                 // ...
                 cout.rdbuf(&buf_cout);
                 cin.rdbuf(&buf_cin);
                 cerr.rdbuf(&buf_cerr);
                 clog.rdbuf(&buf_cerr);
                 // ...
              }
            return __ret;
          }

          從上述代碼,進(jìn)一步驗(yàn)證了我們上面的說法,如果禁用了同步功能,則C++流使用自己的緩沖區(qū)buf_cin(此處以cin為例),幾種buffer的定義如下:

           typedef char fake_filebuf[sizeof(stdio_filebuf<char>)]
            __attribute__ ((aligned(__alignof__(stdio_filebuf<char>))));
            fake_filebuf buf_cout;
            fake_filebuf buf_cin;
            fake_filebuf buf_cerr;

          好了,截止到現(xiàn)在,我們已經(jīng)搞清楚了為什么C++流性能要慢于C,為了驗(yàn)證是否真的是因?yàn)槭褂昧送焦δ芏鴮?dǎo)致的性能差異,使用std::ios::sync_with_stdio(false)關(guān)閉同步,代碼示例如下:

          #include <chrono>

          #include <functional>
          #include <iostream>
          #include <fstream>
          const int num=1000000;

          void time_report(const std::function<void()> &f1, const std::function<void()> &f2) {
             auto start = std::chrono::high_resolution_clock::now();
             f1();
             auto end = std::chrono::high_resolution_clock::now();
             std::cout << "cin cost " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms" << std::endl;

             start = std::chrono::high_resolution_clock::now();
             f2();
             end = std::chrono::high_resolution_clock::now();
             std::cout << "scanf cost " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms" << std::endl;
          }


          void write() {
            std::ofstream file("./data");
            for(int i = 0; i < num; ++i) {
              file << rand() <<' ';
              if((i + 1) % 20 == 0) {
                file << std::endl;
              }
            }
          }
          int main() {
            std::ios::sync_with_stdio(false);
            write(); 
            
            time_report([](){
            freopen("./data","r",stdin);
            int n = 0;
            for(int i=0; i<num; i++) {
                std::cin >> n;
            }
          }, [](){
            freopen("./data","r",stdin);
            int n = 0;
            for(int i = 0; i < num; ++i) {
               scanf("%d", &n);
            }
          });

          return 0;
          }

          編譯,運(yùn)行后,輸出如下:

          cin cost 178ms
          scanf cost 189ms

          可以看出禁用同步后,二者的性能基本一致。

          既然禁用同步后,C++流的性能與C基本一致,那么是否直接禁用呢?答案是依賴于具體的使用場(chǎng)景。

          1、同步的C++流是線程安全的,也就說來自不同線程的輸出可能會(huì)交錯(cuò),但數(shù)據(jù)不會(huì)產(chǎn)生競(jìng)爭(zhēng),而如果禁用同步,則可能出現(xiàn)意想不到的結(jié)果。

          2、如果禁用了同步功能,輸入輸出順序可能會(huì)得不到我們想要的結(jié)果。

          #include <stdio.h>
          #include <iostream>

          int  main() {
            std::cout << "a ";
            printf("b ");
            std::cout << "c ";
            return 0;
          }

          上述代碼執(zhí)行后,輸出a b c ,符合我們的預(yù)期。

          如果加上禁用同步代碼,如下:

          #include <stdio.h>
          #include <iostream>

          int  main() {
          std::ios_base::sync_with_stdio(false);
          std::cout << "a ";
          printf("b ");
          std::cout << "c ";

          return 0;
          }

          編譯、運(yùn)行之后,結(jié)果為a c b,與我們期望的不一致。

          結(jié)語

          如果使用C編程,那么使用C stdio,而如果使用C++編程,則建議使用C++ I/O。如果在某些特殊場(chǎng)景下,需要混合使用,那么強(qiáng)烈建議不要禁用同步,否則會(huì)得到意想不到的結(jié)果。

          好了,今天的文章就到這,我們下期見!

          瀏覽 37
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  激情乱伦麻豆 | 久草视频福利在线 | a人妻免费视频 | 国产乱码一区二区 | 国产av最新福利 国产jk在线观看 |