Если вы хотите здесь получить реальное распараллеливание, используйте
GCC с оптимизацией векторизации дерева (-O3) и SIMD (например, -march = native для получения поддержки SSE).Если операция (dostuff) нетривиальна, вы можете сделать это раньше времени (std::transform
или std::for_each
) и накапливать следующее (std::accumulate
), так как накопление будет оптимизировано, как ничто другое в инструкциях SSE!
void apply_function(double& value)
{
value *= 3; // just a sample...
}
// ...
std::vector<double> data(1000);
std::for_each(data.begin(), data.end(), &apply_function);
double sum = std::accumulate(data.begin(), data.end(), 0);
Обратите внимание , что, хотя это на самом деле не будет выполняться в нескольких потоках, увеличение производительности будет огромным, поскольку инструкции SSE4 могут обрабатывать многие плавающие операции * в параллели _на одном ядре_.
Если вы хотели истинного параллелизма, используйте один из следующих
Компиляцияс g++ -fopenmp -D_GLIBCXX_PARALLEL
:
__gnu_parallel::accumulate(data.begin(), data.end(), 0.0);
Компиляция с g++ -fopenmp
double sum = 0.0;
#pragma omp parallel for reduction (+:sum)
for (size_t i=0; i<data.end(); i++)
{
sum += do_stuff(i, data[i]);
}
Это приведет к параллелизации циклана столько потоков (команда OMP), сколько есть (логических) ядер ЦП на реальной машине, и результат «волшебным образом» объединяется и синхронизируется.
Заключительные замечания:
Вы можете смоделировать двоичную функцию для for_each, используя stateful функциональный объект.Это не совсем рекомендуемая практика.Это также будет казаться очень неэффективным (при компиляции без оптимизации это так).Это связано с тем, что функциональные объекты передаются по значению через STL.Однако разумно ожидать, что компилятор полностью оптимизирует потенциальные накладные расходы, особенно для простых случаев, таких как:
struct myfunctor
{
size_t index;
myfunctor() : index(0) {}
double operator()(const double& v) const
{
return v * 3; // again, just a sample
}
};
// ...
std::for_each(data.begin(), data.end(), myfunctor());