简体   繁体   English

std::remove_if GCC 实现效率不高?

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

From another question here there seems to be evidence, that GCC's implementation of std::remove_if doesn't provide equally efficiency compared to the following implementation:这里的另一个问题似乎有证据表明,与以下实现相比,GCC 对std::remove_if实现没有提供同等的效率:

'raw homebrew' solution : “原始自制”解决方案

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';

Timing outputs:定时输出:

0.106860 0.106860

Sample benchmarking code for std::remove_if for a solution of the same problem:用于解决同一问题的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);

Timing outputs:定时输出:

1.986838 1.986838

Check and get actual runtime results for the code running the ideone links above please (giving the full codes here would obscure the question!).请检查并获取运行上面 ideone 链接的代码的实际运行时结果(在此处提供完整代码会使问题变得模糊!)。

Given the provided execution time results (from the samples), these seem to confirm the first implementation is having much better performance.鉴于提供的执行时间结果(来自示例),这些似乎证实第一个实现具有更好的性能。

Can anyone tell reasons, why the std::remove_if() algorithm doesn't (or can't) provide a similarly efficient solution for the given problem?谁能说出原因,为什么std::remove_if()算法没有(或不能)为给定的问题提供类似的有效解决方案?

Looks to me as though you're running remove_if on a range of 100 characters since size is 100, but the "homebrew" runs until you find the nul terminator (which is only 10 characters in).在我看来,由于size为 100,您似乎在 100 个字符的范围内运行remove_if ,但“自制程序”运行直到您找到 nul 终止符(其中只有 10 个字符)。

Dealing with that using the change in your comment below, on GCC with -O2 I still see a difference of about a factor of 2, with remove_if being slower.使用下面评论中的更改处理该问题,在使用 -O2 的 GCC 上,我仍然看到大约 2 倍的差异, remove_if速度较慢。 Changing to:更改为:

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

gets rid of almost all of this difference, although there may still be a <10% difference.消除了几乎所有这些差异,尽管可能仍然存在 <10% 的差异。 So that looks to me like a quality of implementation issue, whether or not the test gets inlined although I haven't checked the assembly to confirm.所以这在我看来像是一个实现质量问题,尽管我没有检查程序集以确认测试是否被内联。

Since your test harness means that no characters are actually removed after the first pass, I'm not troubled by a 10% difference.由于您的测试工具意味着在第一次通过后实际上没有删除任何字符,因此我不会因 10% 的差异而感到困扰。 I'm a bit surprised, but not enough to really get into it.我有点惊讶,但还不足以真正进入它。 YMMV :-) YMMV :-)

You can try to use the erase-remove idiom for a small improvement.您可以尝试使用擦除-删除习语进行小幅改进。

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) );
}

This is combined with the other issue Steve Jessop mentioned, so I replaced size - 1 with 10 but you can use strlen if you wish.这与 Steve Jessop 提到的另一个问题结合在一起,所以我用10替换了size - 1但如果你愿意,你可以使用strlen For this test, my Makefile looks like:对于这个测试,我的 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 is the erase-remove version, test2 is the remove_if version, and test3 is the other version. test是erase-remove 版本, test2remove_if版本, test3是另一个版本。 Here are the results:结果如下:

 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% )

I omitted the verbose information, and I only ran it 10 times.我省略了冗长的信息,只运行了 10 次。 You can try the tests yourself for a better interpretation of the results.您可以自己尝试测试以更好地解释结果。

Why not using a lambda ?为什么不使用 lambda ?

To remove even int from vector v :要从向量 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;
}

normal outputs :正常输出:

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