簡體   English   中英

std :: string處理短字符串的性能

[英]std::string performance for handling short strings

Bjarne Stroustrup和其他專家在Bjarne Stroustrup的文章我之前的問題中說,C ++處理短字符串的速度比C快。

但是在我的測試中, C++C慢了約110%。

g ++版本為4.4.6(在CentOS 6.3上運行)。 這是因為g ++ 4.4.6具有較少的c ++ 11功能(例如Rvalue Reference (move semantics)嗎?

測試結果

$ time a.out input_file輸出減去不調用compose_X()函數的執行時間

  • cpp版本:0.192秒
  • C版本:0.091秒

源代碼

-O2編譯

編輯

compose_cpp()compose_p()來自Bjarne的文章。 他說compose_cpp()compose_p() 我想通過實際測試來檢查這個事實。

如果我以錯誤的方式測試,如何改善測試?

#include <iostream>
#include <fstream>

#include <cstdlib>
#include <cstring>

std::string compose_cpp(const std::string& name, const std::string& domain)
{
    return name + '@' + domain;
}

char* compose_c(const char* name, const char* domain)
{
    char* res = (char*) malloc(strlen(name)+strlen(domain)+2);
    char* p = strcpy(res,name);

    p += strlen(name);
    *p = '@';
    strcpy(p+1,domain);

    return res;
}

int main(int argc, char* argv[])
{
    std::ifstream ifs;
    ifs.open(argv[1]);

    std::string email, domain;

    while (ifs.good())
    {
        ifs >> email;
        ifs >> domain;

        // std::string composed = compose_cpp(email, domain);

        char* composed = compose_c(email.c_str(), domain.c_str());
        free(composed);
    }

    ifs.close();
}

輸入文件

輸入文件的長度為1毫米。 每行少於20個字節,是隨機生成的。

$ head -n 10 input.txt.1m
9742720 1981857.com
22504 4127435.com
342760 69167.com
53075 26710.com
3837481 1851920.com
98441 278536.com
4503887 9588108.com
193947 90885.com
42603 8166125.com
3587671 297296.com

我只是在這里猜測,因為我沒有要測試的數據文件。 我認為您的結果可能與Stroustrup的期望不符,因為他在這里說的是:

是的,C ++版本,因為它不必計算參數字符,並且不為簡短的參數字符串使用免費存儲(動態內存)。

但是,我的理解是libstdc++對所有字符串(零長度字符串除外)使用動態內存。 請參閱最近對libstdc++ std::string對象的小尺寸問題的答案: https : //stackoverflow.com/a/27631366/12711

使用短字符串優化的實現可能會帶來更好的結果(例如MSVC-我不確定clang的libc ++是否使用它)。

我可以隨意擴展測試程序。 特別是,我添加了代碼以使其在內部生成其數據,而不是依賴於外部文件,添加了計時代碼以隔離所討論的字符串處理,並使其在同一運行中同時執行C ++和C版本的字符串處理,因此立即產生了可以比較的結果。 那給了我下面的代碼:

#include <iostream>
#include <fstream>
#include <vector>
#include <string>

#include <cstdlib>
#include <cstring>

#include <ctime>

char* compose_c(const char* name, const char* domain)
{
    char* res = (char*) malloc(strlen(name)+strlen(domain)+2);
    char* p = strcpy(res,name);

    p += strlen(name);
    *p = '@';
    strcpy(p+1,domain);

    return res;
}

std::string rand_string(int size){
    std::string ret;

    for (int i = 0; i < size; i++)
        ret.push_back(rand() % 10 + '0');
    return ret;
}

struct address {
    std::string email, domain;

    address() : email(rand_string(5)), domain(rand_string(4) + ".com") { }
};

struct composed {
    std::string addr;
    composed(address const &a) : addr(a.email + "@" + a.domain) {}
};

void report(clock_t d, std::string const &label){
    std::cout << double(d) / CLOCKS_PER_SEC << " seconds for " << label << "\n";
}

int main(int argc, char **argv) {
    static const int NUM = 1024 * 1024;

    std::vector<address> addresses(NUM);

    clock_t start = clock();
    {
        std::vector<composed> c{ addresses.begin(), addresses.end() };
    }
    report(clock() - start, "C++");

    std::vector<char *> c_results(addresses.size());

    clock_t start_c = clock();
    for (int i = 0; i < addresses.size(); i++)
        c_results[i] = compose_c(addresses[i].email.c_str(), addresses[i].domain.c_str());
    for (char *c : c_results)
        free(c);
    report(clock() - start_c, "C");
}

然后,我使用VC ++ 2013 x64使用以下標志-O2b2 -GL -EHsc進行了編譯: -O2b2 -GL -EHsc 當我運行它時,我得到的結果是:

0.071 seconds for C++
0.12 seconds for C

盡管每次運行之間都有一些差異,但是這些結果是非常有代表性的-C代碼花費的時間幾乎是(但不是完全)兩倍於C ++代碼。

請注意,盡管事實上我已經給C版本帶來了一些不公平的優勢。 C ++代碼的時間不僅包括執行字符串操作的時間,還包括創建和銷毀向量以保存結果的時間。 對於C代碼,我提前准備了向量,然后僅對代碼計時,以創建和銷毀字符串本身。

為確保此結果不是偶然,我還嘗試更改一些自變量。 例如,將我們編寫的地址字符串的數量增加10倍,會增加總時間,但對比率幾乎沒有影響:

0.714 seconds for C++
1.206 seconds for C

同樣,更改順序以使C代碼首先運行,然后C ++代碼沒有明顯效果。

我想我應該補充一下:這是真的,因為它的立場,這個代碼不實際使用compose_cpp功能作為原始一樣,選擇納入的功能集成到構造函數composed代替。 為了完整起見,我確實編寫了一個使用compose_cpp的版本,如下所示:

std::vector<std::string> composed;
composed.reserve(NUM);

clock_t start = clock();

for (auto const &a : addresses)
    composed.push_back(compose_cpp(a.email, a.domain));

這實際上改善了時序,但是我想這主要是由於將時間用於創建向量本身的時間從時序代碼中移出了,並且並沒有太大的區別來關心:

0.631 seconds for C++
1.21 seconds for C

盡管這些結果確實在很大程度上取決於標准庫的實現,特別是std::string實現了短字符串優化這一事實。 運行在相同的硬件相同的代碼,但使用缺乏這種優化(GCC 4.9.1的nuwen MinGW的分布,在我的情況)給出了完全不同的結果的實現:

2.689 seconds for C++
1.131 seconds for C

在這種情況下,C代碼比VC ++中的代碼快一點,但是C ++代碼的速度降低了大約4倍。我嘗試了一些不同的編譯器標志(-O2與-O3等),但是它們具有只有最小的影響-對於此測試,缺少短字符串優化顯然是其他因素的主導。

底線:我認為這證實了C ++代碼可以比C代碼快得多, 但是達到這一速度很大程度上取決於實現的質量。 如果實現未能提供短字符串優化,則C ++代碼很容易比C版本慢2倍,而不是快2倍。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM