C++并发实战5:并行化的std::accumulate

原创 2013年12月04日 16:46:21

            std::thread::hardware_concurrency()可以返回CPU个数,在C++库不能获取CPU信息下可能返回0。该信息是非常有用的,当线程数超过CPU cores会频繁的引起上下文切换,返回会降低性能,当hardware_concurrency()返回0时可以指定一个数目比如2。

          下面给出一个并行化的std::accumulate()的例子:std::accumulate(first,last,init,fun)的语义是在一个初始值init前提下将一个[first,last)序列的元素与init执行fun函数。默认fun=NULL是将[first,last)的所有元素加起来再加上init得到序列的累加值。现在并行化:将序列拆分成子序列然后每个子序列的求和由一个线程执行,然后将各个线程的累加值再求和。有点类似于MapReduce的wordcount。

#include<iostream>
#include<thread>
#include<numeric>
#include<algorithm>
#include<functional>
#include<vector>
using namespace std;
template<typename Iterator,typename T>
struct accumulate_block{
    void operator()(Iterator first,Iterator last,T& result){//每个子序列累加,不能通过线程的返回值返回累加结果,而是通过一个result引用将结果返回给主线程
        result=std::accumulate(first,last,result);
    }
};

template<typename Iterator,typename T>
T parallel_accumulate(Iterator first,Iterator last,T init)
{
    unsigned long const length=std::distance(first,last);//计算序列的长度
    if(!length)//若序列为空直接返回init
        return init;
    unsigned long const min_per_thread=25;//每个线程的子序列大小
    unsigned long const max_threads=(length+min_per_thread-1)/min_per_thread;//计算线程数(向上取整)
    unsigned long const hardware_threads=std::thread::hardware_concurrency();//获取PC的CPU core数目,C++库可能无法访问该信息,所以可能返回0
    unsigned long const num_threads=std::min(hardware_threads!=0?hardware_threads:2,max_threads);//最大线程数在计算出来的最大线程数和硬件core数目中取较小者(线程数超过core数目反而降低性能)
    unsigned long const block_size=length/num_threads;//重新计算每个线程需要执行的序列大小
    vector<T> results(num_threads);//每个线程的结果将保存在results中
    vector<thread> threads(num_threads-1);//开启线程池,只用开启num_threads-1个子线程,因为主线程也可以计算一个序列
    Iterator block_start=first;//序列开始位置
    for(int i=0;i<(num_threads-1);i++){//这里只分配子线程的任务序列
        Iterator block_end=block_start;
        std::advance(block_end,block_size);//迭代器block_end向前移动block_size
        threads[i]=thread(accumulate_block<Iterator,T>(),block_start,block_end,std::ref(results[i]));//每个子线程的子序列分配
        block_start=block_end;//更新序列位置
    }
    accumulate_block<Iterator,T>()(block_start,last,results[num_threads-1]);//主线程的任务,注意是last
    std::for_each(threads.begin(),threads.end(),std::mem_fn(&thread::join));//等待子线程完成
    return std::accumulate(results.begin(),results.end(),init);//汇总结果
}
int main(){
    vector<int> vec;
    for(int i=0;i<100;i++){
        vec.push_back(10);
    }
    int sum=parallel_accumulate(vec.begin(),vec.end(),5);
    cout<<"sum="<<sum<<endl;
    return 0;
}

程序输出:

sum=1005



c++ 并行编程

本博客将看C++并行编程的例子 首先看如何看 #include #include using namespace std; int main() { clock_t startTime...
  • andeyeluguo
  • andeyeluguo
  • 2017年05月02日 17:30
  • 1014

Visual Studio 11开发指南(19)C++11更新-并行模式库和代理库

Visual Studio 11,具备并行模式库和代理库、 更轻松地开发多核处理器上运行的并行代码。这些库的主要范例是根据任务 和并发运行库,自定义的调度程序 进行处理的。 到目前为止,处理任务的的概...
  • yincheng01
  • yincheng01
  • 2012年01月16日 06:47
  • 5342

[并发并行]_[C/C++]_[C++标准库里的线程安全问题]

场景1.写普通的程序时, 经常会使用cout来做输出, 每个进程只有一个控制台, 如果多线程调用cout时会出状况吗?2.之所以研究cout会不会在并发下调用有问题, 是因为曾经有一个bug的崩溃点正...
  • infoworld
  • infoworld
  • 2017年01月14日 15:55
  • 1818

TBB/OpenMP/raw thread三种并发编程的取舍分析

繁简程度考虑因素 与 OpenMP 或英特尔® 线程构建模块(TBB)相比,本地线程编程模式采用了更为复杂的代码,因而其维护工作的难度也就相对较大。这样,您在适当的情况下,不妨使用英特尔® TBB...
  • yuwei629
  • yuwei629
  • 2013年07月11日 16:52
  • 2484

C++11:基于std::unordered_map和共享锁构建线程安全的map

前一篇博客《C++:基于std::queue和std::mutex构建一个线程安全的队列》中,我们实现了一个线程安全的队列,本文我们说说如何实现一个线程安全的map。 在上一篇博客中,实现threa...
  • 10km
  • 10km
  • 2016年07月30日 12:36
  • 4839

C++中密集运算的并行化(OpenMP,PPL)

test
  • zjjzhaohang
  • zjjzhaohang
  • 2017年06月16日 17:48
  • 220

有关对耗时很大循环进行并行化优化的探讨 之一:并发搜索的处理

在对程序优化过程中,我们往往对循环体有着刻骨的仇恨,因为它对性能的损耗尤其之大,比如如下例程,是个简单的循环例程,全部执行需要30秒以上(痛苦):   public enum HandleRst ...
  • etudiant6666
  • etudiant6666
  • 2012年03月09日 13:57
  • 3193

【C++ STL应用与实现】86: 如何使用std::accumulate

本文总结了STL算法中,数值类算法(numeric algorithm)里的第一个算法: std::accumulate的使用, 及注意事项...
  • elloop
  • elloop
  • 2015年12月18日 09:45
  • 9043

有关对耗时很大循环进行并行化优化的探讨之二:多重循环任务的并发处理

【引】 在上一篇有关并行化的《有关对耗时很大循环进行并行化优化的探讨 之一:并发搜索的处理》博文中,我们看到,不使用并行语言,而使用基本的编程语言配合多线程可以进行并行化处理,本文进一步将并行化操作...
  • etudiant6666
  • etudiant6666
  • 2012年04月02日 21:05
  • 2578

哼唱检索的并行化方法研究与实现

  • 2014年03月18日 10:36
  • 1.88MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++并发实战5:并行化的std::accumulate
举报原因:
原因补充:

(最多只允许输入30个字)