簡體   English   中英

std::remove_if GCC 實現效率不高?

[英]std::remove_if GCC implementation isn't efficient?

這里的另一個問題似乎有證據表明,與以下實現相比,GCC 對std::remove_if實現沒有提供同等的效率:

“原始自制”解決方案

static char str1[100] = "str,, ing";
size_t size = sizeof(str1)/sizeof(str1[0]);

int bad = 0;
int cur = 0;
while (str1[cur] != '\0') {
    if (bad < cur && !ispunct(str1[cur]) && !isspace(str1[cur])) {
        str1[bad] = str1[cur];
    }
    if (ispunct(str1[cur]) || isspace(str1[cur])) {
        cur++;
    } else {
        cur++;
        bad++;
    }
}
str1[bad] = '\0';

定時輸出:

0.106860

用於解決同一問題的std::remove_if示例基准代碼

bool is_char_category_in_question(const char& c) {
    return std::ispunct(c) || std::isspace(c);
}

std::remove_if(&str1[0], &str1[size-1], is_char_category_in_question);

定時輸出:

1.986838

請檢查並獲取運行上面 ideone 鏈接的代碼的實際運行時結果(在此處提供完整代碼會使問題變得模糊!)。

鑒於提供的執行時間結果(來自示例),這些似乎證實第一個實現具有更好的性能。

誰能說出原因,為什么std::remove_if()算法沒有(或不能)為給定的問題提供類似的有效解決方案?

在我看來,由於size為 100,您似乎在 100 個字符的范圍內運行remove_if ,但“自制程序”運行直到您找到 nul 終止符(其中只有 10 個字符)。

使用下面評論中的更改處理該問題,在使用 -O2 的 GCC 上,我仍然看到大約 2 倍的差異, remove_if速度較慢。 更改為:

struct is_char_category_in_question {
    bool operator()(const char& c) const {
        return std::ispunct(c) || std::isspace(c);
    }
};

消除了幾乎所有這些差異,盡管可能仍然存在 <10% 的差異。 所以這在我看來像是一個實現質量問題,盡管我沒有檢查程序集以確認測試是否被內聯。

由於您的測試工具意味着在第一次通過后實際上沒有刪除任何字符,因此我不會因 10% 的差異而感到困擾。 我有點驚訝,但還不足以真正進入它。 YMMV :-)

您可以嘗試使用擦除-刪除習語進行小幅改進。

std::string str{str1};
for(i=0;i<999999L;++i) {
    str.erase( std::remove_if(std::begin(str), std::end(str), is_char_category_in_question), std::end(str) );
}

這與 Steve Jessop 提到的另一個問題結合在一起,所以我用10替換了size - 1但如果你願意,你可以使用strlen 對於這個測試,我的 Makefile 看起來像:

compile:
    g++ test.cpp -o test -std=c++11 -O3
    g++ test2.cpp -o test2 -std=c++11 -O3
    g++ test3.cpp -o test3 -std=c++11 -O3
run:
    perf stat -r 10 ./test
    perf stat -r 10 ./test2
    perf stat -r 10 ./test3

test是erase-remove 版本, test2remove_if版本, test3是另一個版本。 結果如下:

 Performance counter stats for './test' (10 runs):

       0.035699861 seconds time elapsed                                          ( +-  2.30% )

perf stat -r 10 ./test2

 Performance counter stats for './test2' (10 runs):

       0.050991938 seconds time elapsed                                          ( +-  2.96% )

perf stat -r 10 ./test3

 Performance counter stats for './test3' (10 runs):

       0.038070704 seconds time elapsed                                          ( +-  2.34% )

我省略了冗長的信息,只運行了 10 次。 您可以自己嘗試測試以更好地解釋結果。

為什么不使用 lambda ?

要從向量 v 中刪除偶數 int :

int main (int argc, char* argv []) {
  int tmp [5] = {1, 2, 4, 5, 7};
  int* p ((int*) tmp);
  std::vector<int> v (p, p+5);
  std::cout << "v init :";
  for (auto i (v.begin ()); i != v.end (); ++i) std::cout << *i << " ";
  std::cout << std::endl;

  auto i (v.begin ());
  std::for_each (v.begin (), v.end (), [&i] (const int s) {
    if (s%2) *i++ = s;
  });

  if (i != v.end ()) v.erase (i, v.end ());

  std::cout << "v odd :";
  for (auto i (v.begin ()); i != v.end (); ++i) std::cout << *i << " ";
  std::cout << std::endl;
}

正常輸出:

v init :1 2 4 5 7 
v odd :1 5 7 

暫無
暫無

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

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