我实现了一个parallel_accumulate,类似于std :: acumulate但是使用线程来并行化累积工作。 有两个版本的std :: accumulate,第二个带有一个额外的运算符用于累积,而第一个隐式假设添加..第一个版本:
template<typename Iterator, typename T>
static T parallel_accumulate(Iterator first, Iterator last, T init)
{
unsigned long const length = std::distance(first, last);
if (!length) return init;
unsigned long const max_ths = 64;
unsigned long const hw_ths = std::thread::hardware_concurrency();
unsigned long const num_ths = std::min(hw_ths != 0 ? hw_ths : 2, max_ths);
unsigned long const block_size = length / num_ths;
std::vector<T> results(num_threads);
std::vector<std::thread> threads(num_ths);
Iterator block_start = first;
for (unsigned long i = 0; i < num_ths; ++i) {
Iterator block_end = block_start;
std::advance(block_end, block_size);
threads[i] = std::thread( // diff1
_noop<Iterator,T>(),
block_start,
block_end,
std::ref(results[i]));
block_start = block_end;
}
std::for_each(threads.begin(), threads.end(),std::mem_fn(&std::thread::join));
return std::accumulate(results.begin(), results.end(), init); // diff2
}
第二版:
template<typename Iterator, typename T, typename BinOp>
static T parallel_accumulate(Iterator first, Iterator last, T init, BinOp op)
{
unsigned long const length = std::distance(first, last);
if (!length) return init;
unsigned long const max_ths = 64;
unsigned long const hw_ths = std::thread::hardware_concurrency();
unsigned long const num_ths = std::min(hw_ths != 0 ? hw_ths : 2, max_ths);
unsigned long const block_size = length / num_ths;
std::vector<T> results(num_threads);
std::vector<std::thread> threads(num_ths);
Iterator block_start = first;
for (unsigned long i = 0; i < num_ths; ++i) {
Iterator block_end = block_start;
std::advance(block_end, block_size);
threads[i] = std::thread( // diff1
_op<Iterator,T,BinOp>(),
block_start,
block_end,
std::ref(results[i]));
block_start = block_end;
}
std::for_each(threads.begin(), threads.end(),std::mem_fn(&std::thread::join));
return std::accumulate(results.begin(), results.end(), init, op); // diff2
}
您可以很容易地看到我的两个版本的实现仅在两行上有所不同,我如何避免在C ++中优雅地复制此代码(即不使用#defines)?
(请注意,为了清楚起见,我省略了_noop和_op,它们只是调用各个版本的std :: accumulate的可调用结构)
更新:我希望拥有第一个没有显式添加运算符的版本(因为隐式std :: accumulate更快)。
答案 0 :(得分:4)
如果你有C ++ 14透明操作符仿函数,那么第一个版本可以实现为
template<typename Iterator, typename T>
static T parallel_accumulate(Iterator first, Iterator last, T init)
{
return parallel_accumulate(first, last, init, std::plus<>());
}
如果不这样做,则等同于std::plus<>
只是
struct my_plus {
template<class T, class U>
auto operator()(T&& t, U&& u) const -> decltype(std::forward<T>(t) + std::forward<U>(u)) {
return std::forward<T>(t) + std::forward<U>(u);
}
};