TL;DR:以明显的方式进行,并确保您的编译器对其进行了优化。
如果没有完整的、可重现的程序示例,就很难推断性能。所以让我们从一个简单的实现开始:
#include <array>
#include <algorithm>
std::array<int, 362856427> a = {};
int main()
{
a[500] = 1;
a[5000] = 1;
a[50000] = 1;
a[500000] = 1;
auto counter = 0u;
for (auto i = 0u; i < a.size(); ++i) {
if (a[i] != 1)
++counter;
}
return counter != 362856423;
}
计时,我得到了 1.79 秒的用户时间。然后我意识到我的错误,并添加-O3
到我的编译命令中。这更好:
g++ -std=c++17 -g -Wall -Wextra -O3 16385733.cpp -o 16385733
time ./16385733
0.07user 0.08system 0:00.16elapsed 98%CPU (0avgtext+0avgdata 2212maxresident)k
我们可以尝试简化循环,但这并没有明显的区别(优化器已经击败了我们):
for (auto i = 0u; i < a.size(); ++i)
counter += a[i] != 1;
另一种选择是通过使用标准算法使代码更清晰:
auto counter = a.size() - std::count(a.begin(), a.end(), 1);
这始终比明显的循环花费 50% 的时间。
如果您的输入数组要大得多,您可以通过像这样并行化计算来获得收益:
auto counter = 0ul;
#pragma omp parallel for reduction(+:counter)
for (auto i = 0ul; i < a.size(); ++i)
counter += a[i] != 1;
我的基准测试表明,当数组大小为 362856427 时,它与标准算法一样慢,而当它增加到 3628564270 时,速度不会更快。
有几种方法可以以等效形式重写:
for (auto i: a)
counter += i != 1;
for (auto p = a.data(); p < end; ++p)
counter += *p != 1;
所有这些都表现出相似的性能,并且没有通过 OpenMP 得到改进。
所以简短的回答是
- 以明显的方式做
- 确保您的编译器正在优化,并且
- 对您的替代方案进行基准测试。