前缀和并行算法

mpi求前缀和  1.数据分成n份(n是进程数),然后每个进程单独求和, 2.把每个进程的最后一位数传到下面的进程里面。然后在每个接下来的进程里面最后一位数加上这个数,此时每个进程的最后一位数都是真正的前缀和 3.把每一个进程的的最后一位数传到下面一个进程,下面那个进程里面除了最后一位数,其他所有数都加上这个数。求得前缀和。 4.收集到一起。 下面是代码: /* 1.求前缀和,利用的方法是sc 阅读详情

多核中的并行前缀和计算

前缀和计算在并行计算中很有用,因为在处理负载平衡问题时,经常需要将若干段数据重新平分,计算前缀和通常是一种有效的将数据平分的方法。例如在并行基数排序中,就会用到了前缀和的计算。而下面先看看单线程环境中的串行前缀和计算。

1、串行前缀和的计算

如果给定一个数列a[n],令S[k] = a[0]+a[1]+...+a[k],(k = 0, 1, 2…n-1),数列S[k]即为数列a[n]的前缀和。例如下面一列数据:

a[4] = {1,   2,   3,   4};

其前缀和为

S[0] = a[0] = 1;

S[1] = a[0] + a[1] = 1+ 2 = 3;

S[2] = a[0] + a[1] + a[2] = 1 + 2 + 3 = 6;

S[3] = a[0] + a[1] + a[2] + a[3] = 1 + 2 + 3 + 4 = 10;

前缀和的计算非常简单,一般地,可以用下面的函数来进行串行前缀和的计算:

/**   串行前缀和计算函数

 

       @param  T * pInput - 输入数据 

       @param  T *pOutput - 输出数据(前缀和)   

       @param  int nLen - 输入数据长度     

       @return  void - 无

*/

template <class T>

void Sequential_PrefixSum(T * pInput, T *pOutput, int nLen)

{

    int i;

 

    pOutput[0] = pInput[0];

    for ( i = 1; i < nLen; i++ )

    {

        pOutput[i] = pInput[i] + pOutput[i-1];

    }

}

 

在上面的串行前缀和计算代码中可以看出,每次循环都依赖于上一次循环的结果,因此无法直接对循环进行并行化,要进行并行化则必须修改计算方法,下面就来看如何进行并行前缀和的计算。

2、并行前缀和的计算

前缀和的并行计算方法有许多种,David Callahan的论文“Recognizing and Parallelizing Bounded Recurrences”中给出了一种适合共享存储多处理器系统中的有界递归计算的通用方法,前缀和计算属于有界递归计算的一个特例。下面先以一个实例来讲解整个并行计算的过程:

例:假设有4个处理器要计算16个整数的前缀和,这16个整数如下:

1   2   3   4   5   6   7   8   9   10   11   12   13   14   15   16

第1步,先将上面数据平分成4组,每个处理器各计算一组数据的前缀和,如下所示:

(1   2   3   4) (5   6   7   8) (9   10   11   12) (13   14   15   16)

(1   3   6   10) (5   11   18   26) (9   19   30   42) (13   27   42   58)

第2步,选取每组数据的最后一个数据,对这几个数据计算前缀和,如下所示:

(1  3  6   10) (5   11   18   26) (9   19   30   42) (13   27   42  58)

(1  3  6   10) (5   11   18   36) (9   19   30   78) (13   27   42  136)

经过这步的计算后,可以很容易发现,每组的最后一个数据的值已经变成了原始数据在它所处位置之前(包含本位置)的所有数据的和。例如:

36 = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8

78 = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12

第3步:从第2组数开始,将每组中的数(除最后一个数外)加上它的前一组数的最后一个数,即可得到所有数的前缀和。如下所示:

 (1 3 6 10) (5+10 11+10 18+10 36) (9+36 19+36 30+36 78)  (13+78 27+78 42+78 136)

(1  3  6  10)  (15  21  28  36)  (45  55  66  78)  (91  105  120  136)

从上面的计算过程可以看出,第1步和第3步都是很容易进行并行化计算,第2步中,由于计算量非常小,用串行计算即可,下面给出上面处理过程的代码实现:

#define  MIN_PRARLLEL_PREFIXSUM_COUNT    8192

 

/**   并行前缀和计算函数

 

       @param  T * pInput - 输入数据 

       @param  T *pOutput - 输出数据(前缀和)   

       @param  int nLen - 输入数据长度     

       @return  void - 无

*/

template<class T>

void Parallel_PrefixSum(T * pInput, T *pOutput, int nLen)

{

    int i;

 

    int nCore = omp_get_num_procs();

 

       if ( nCore < 4 || nLen < MIN_PRARLLEL_PREFIXSUM_COUNT )

    {

        Sequential_PrefixSum(pInput, pOutput, nLen);

        return;

    }

 

       int nStep = nLen / nCore;

    if ( nStep * nCore < nLen )

    {

        nStep += 1;

    }

 

#pragma omp parallel for num_threads(nCore)

    for ( i = 0; i < nCore; i++ )

    {

        int k;

        int nStart = i * nStep;

        int nEnd = (i+1) * nStep;

        if ( nEnd > nLen )

        {

            nEnd = nLen;

        }

        pOutput[nStart] = pInput[nStart];

        for ( k = nStart+1; k < nEnd; k++ )

        {

            pOutput[k] = pInput[k] + pOutput[k-1];

        }

    }

 

    for ( i = 2; i < nCore; i++ )

    {

        pOutput[i * nStep - 1] += pOutput[(i-1) * nStep - 1];

    }

 

    pOutput[nLen-1] += pOutput[(nCore-1)*nStep - 1];

 

#pragma omp parallel for num_threads(nCore-1)

    for ( i = 1; i < nCore; i++ )

    {

        int k;

        int nStart = i * nStep;

        int nEnd = (i+1) * nStep - 1;

        if ( nEnd >= nLen )

        {

            nEnd = nLen - 1;

        }

        for ( k = nStart; k < nEnd; k++ )

        {

            pOutput[k] += pOutput[nStart-1];

        }

    }

    return;

}

从上面并行前缀和的计算过程可以看出,它的计算量比串行前缀和的计算增加了差不多一倍,如果考虑程序中的实际开销,计算增加量还不止一倍。因此在双核CPU机器上,使用并行前缀和计算没有任何意义,只有在超过4核CPU机器上,它才有实用价值。

Parallel_PrefixSum()函数中,先是判断CPU核数是否小于4,并且判断了计算量是否不足,如果两个判断条件中有任何一个满足,则调用串行前缀核计算函数进行计算,然后才进行并行前缀和的计算。在并行计算时只是简单地将计算平摊到各个CPU上,没有考虑CPU核数较多情况下计算量平摊到各个CPU核上,线程粒度过小的问题,主要是为了不使代码看起来过于繁琐。如有需要可以修改成自动计算出最合适的线程数量(可能小于CPU核数),然后并行计算时使用相应的线程数量即可。



原帖:http://blog.youkuaiyun.com/drzhouweiming/article/details/3164974

【并行计算】前缀和并行思路 一.定义如果给定一个数列a[n],令S[k] = a[0]+a[1]+…+a[k],(k = 0, 1, 2…n-1),数列S[k]即为数列a[n]的前缀和。二.串行算法很容易就能想到串行的算法:S[0] = a[0]; for (int i = 1; i < n; i++) S[i] = S[i-1] + a[i];三.并行算法我们用一个实际的例子来说明本问题的并行解题思路。假设有4个处理 阅读详情

相关推荐

Python CUDA并行算法:扫描(Scan)算法 - 前缀和的Work-Efficient并行实现 (12)

Scan(扫描)是一种并行前缀和算法,将输入数组的每个位置替换为该位置之前所有元素的累积结果。# ↑ ↑ ↑ ↑# ↑ ↑ ↑ ↑Exclusive Scan将第i个元素的结果存储在第i+1个位置。从数组中移除所有不满足条件的元素# 输入数组# 条件:保留非零元素# 输出:[3, 5, 2, 1]✅Scan是前缀和的并行实现,应用广泛✅Inclusive Scan包含当前元素,Exclusive不包含✅Hillis-Steele简单但低效(O(N log N) work)✅。

qq_43410673的博客 647

MPI编程中并行前缀和计算

前缀和计算在并行计算中很有用,因为在处理负载平衡问题时,经常需要将若干段数据重新平分,计算前缀和通常是一种有效的将数据平分的方法。例如在并行基数排序中,就会用到了前缀和的计算。而下面先看看单线程环境中的串行前缀和计算。 1、串行前缀和的计算 如果给定一个数列a[n],令S[k] = a[0]+a[1]+...+a[k],(k = 0, 1, 2…n-1),数列S[k]即为数列a[n]的前缀和。

encaidx的专栏 2149

第25节:并行前缀和(Scan)算法详解

内容说明算法核心上升归约 + 下降扫描适用范围大量数据的并行前缀和计算应用领域流式处理、排序、图算法等。

yumeiguo的博客 294

并行计算之并行前缀法(Parallel Prefix)

描述了一种可用于并行化一类问题的算法

高阶近似的博客 3621

7、高效并行算法设计与指针数据结构处理

本文介绍了高效并行算法的设计方法及其在指针数据结构处理中的应用。内容涵盖基于PRAM模型的数组打包、排序与凸包计算算法,以及利用指针跳跃技术在链表、树等数据结构上的并行计算策略。通过分治策略、前缀和计算和欧拉环游等方法,展示了如何将复杂问题高效转换为并行处理任务,以实现最优性能。

fun88的博客 39

8、高效并行算法设计:技术与应用

本文系统介绍了高效并行算法的设计技术与应用,涵盖指针跳跃、前缀和计算和欧拉环游等核心方法,并探讨了带总线的网格模型及其在链表排名、图的连通性等复杂问题中的应用。同时分析了并行算法的性能指标和优化策略,结合图像处理、数据分析和科学计算等实际案例,展望了并行算法的未来发展。

fun88的博客 55

数组的前缀和(Prefix Sum)问题及其并行算法

前缀和(Prefix Sum)问题是在讨论并行优化算法时常常被用来作为示例的一个典型问题。对于一个输入的数组,我们所得之结果是一个等长的数组,而结果数组中的每个元素(假设是第x个元素)都是原数组中对应位置的前x项和,这就是所谓的前缀和问题(时也称累加和cumulative sum)

白马负金羁 1万+

6、高效并行算法设计与实现

本文探讨了高效并行算法在多个领域中的设计与实现,包括矩阵运算、图论问题、数值计算以及计算几何中的凸包问题。分析了图论中基于矩阵乘法的最短路径和最小生成树算法,并讨论了数值计算中矩阵求逆的并行方法。同时,介绍了计算几何中凸包问题的分治法解决方案,并结合PRAM模型探讨了前缀和、数组打包和排序合并等关键技术。文章总结了不同算法的性能特点,并展望了未来优化方向。

fun88的博客 39

并行算法之前缀和

#include #include #include #include #include #include int threadnum = 1025; int n = 0;//n is less than threadnum int A[1025], B[1025][1025], C[1025][1025]; struct param { int i; int j; int value;

Code is to be happy 3401

并行算法设计与分析PPT课件:从理论到课堂的完整教学资源

并行计算通过多处理器协同求解问题,其核心在于计算模型、设计方法与复杂度分析。PRAM模型作为理论基准,定义了并行随机访问机的抽象;分治、划分等设计方法将问题分解为可并行子任务;工作量与深度指标则决定了算法的加速比上限。掌握这些基础,能有效提升大规模数据处理、科学计算等场景的性能。本文分享一份《并行算法的设计与分析》PPT课件,覆盖PRAM模型、并行前缀和、归并排序等经典内容,并附教学编排与避坑指南,助力高校教师与工程师快速开展并行计算教学。

weixin_32821533的博客 256

并行算法设计与分析:从加速比评估到OpenMP实战与性能优化

并行计算已成为多核处理器时代提升程序性能的关键手段,但如何科学评估并行方案的价值、避免多核资源浪费,是开发者普遍面临的难题。并行算法的核心在于将串行任务合理拆分,并通过加速比、效率等指标量化收益,其中Amdahl定律与Gustafson定律分别从固定规模与扩展规模两个视角给出理论边界。在工程实践中,分治、工作池等设计模式为任务拆分提供了通用骨架,而OpenMP是实现共享内存并行编程的主流工具。从并行前缀和到分块矩阵乘法,经典算例展示了数据并行与缓存局部性对性能的决定性影响。同时,数据竞争、伪共享、负载不均等

weixin_29069575的博客 271

并行算法第二讲:并行算法基础知识

并行算法设计与分析课程总结 第二讲:并行算法基础知识 并行计算模型 PRAM模型是重点 并行归约: 前缀和: 先序树遍历: 模型对比: 复杂度度量 重点:加速比 并行算法设计

CodeLuweir 的博客 940

前缀和的并行化

前缀和的并行化,也就是前N项和的并行化思想

高性能并行算法实战:reduce、scan与矩阵乘法的完整实现指南

在现代高性能计算领域,**并行算法优化**已成为提升程序性能的关键技术。本指南将带您深入理解reduce、scan和矩阵乘法等核心并行算法的完整实现方案,帮助您在实际项目中充分发挥多核处理器的计算潜力。💪 ## 什么是并行算法及其重要性 **并行算法优化**通过将计算任务分解为多个子任务,同时在多个处理器核心上执行,从而大幅提升计算效率。无论是科学计算、数据分析还是机器学习应用,掌握并行编程

gitblog_00109的博客 710

迈德威视相机调用( 基于 Linux系统+ OpenCV )

迈德威视相机调用( 基于 Linux系统+ OpenCV )前言一、登录迈德威视官网,下载官方SDK二、代码调用与视频帧处理( 基于 OpenCV )总结 前言     此博客记录了迈德威视工业相机在 Linux 系统下的代码调用及其环境配置,通过 OpenCV 对视频帧进行处理。   一、登录迈德威视官网,下载官方SDK      迈德威视官网 : http://www.mindvision.com.cn/     1. 进入官网后,在服务支持中选择软件下载。    2. 选择Linux系统S.

kkkkkk0729的博客 5675

Multisim电路仿真与实验:包含连续时间系统的模拟、周期信号频谱分析、组合逻辑电路:竞争冒险、数字锁

这些实际系统可以是电的或非电的物理量系统,也可以是经济、军事等非物理量系统。矩形周期信号的幅度和周期保持不变,随着占空比的增加(即脉宽加大),主峰高度越高,主峰宽度越窄,各谱线间隔越窄,主峰包含的谱线数量越少,有效频带宽度越窄,主峰内高次谐波分量越少。输入信号所经路径不同而引起的冒险现象,按短暂尖峰极性的不同,可将冒险分为“0-1-0”型险象(也称“1”型)和“1-0-1”型险象(也称“0”型)理想的正弦波的幅度谱包含1条谱线,证明其只有基频分量,而无谐波分量,如果能测出谐波分量,说明该正弦波已有失真。

Jumpingtigger_35的博客 1万+

CCCL实战教程:从基础到高级的10个并行算法示例

CCCL(CUDA Core Compute Libraries)是NVIDIA提供的一套强大的并行计算库集合,包含Thrust、CUB和libcu++等组件,帮助开发者轻松实现高效的GPU加速算法。本教程将通过10个实用示例,带你从基础到高级掌握CCCL的核心功能,解锁GPU并行计算的强大能力。 ## 一、环境准备与项目搭建 ### 1.1 快速安装CCCL 首先通过Git克隆项目仓库:

gitblog_00352的博客 634

STM32CubeMX实战:FreeRTOS内存管理5种方案全解析(附heap_4避坑指南)

本文深入解析了STM32CubeMX环境下FreeRTOS的5种内存管理方案(heap_1到heap_5),重点介绍了heap_4的优化策略与避坑指南。通过对比分析各方案的特点、性能指标及适用场景,帮助开发者根据项目需求选择最优内存管理策略,提升嵌入式系统开发效率与稳定性。

aa123的博客 618

并行技术/算法详解

!注:本文所有内容均来自 Yan Gu(研顾)知乎专栏 目录前言:多核时代与并行算法1.平衡二叉搜索树(Balanced BSTs)2.NVRAMs 和 Write-Efficient Algorithms3.其它有趣的问题一、计算模型,调度器,和其它1.古老的 PRAM 模型2.Work-depth (work-span) 模型3.调度算法4.我们为什么 care 并行二、前缀和,fork-join 和矩阵乘法1.前缀和 Scan/prefix sum2. Fork-join, nested parall

qq_42364307的博客 2507

研一小白投稿SCI:Applied Intelligence从提交到Under Review的保姆级避坑指南

本文为研一学生提供Applied Intelligence期刊投稿的详细指南,涵盖格式校验、状态解析及审稿回应策略。特别强调声明文件、LaTeX模板的常见错误及应对方法,帮助新手避开高频踩坑点,提升投稿成功率。

weixin_29230805的博客 493

使用python获取同花顺免费版和同花顺远航版自选股数据用于量化交易

在做量化交易时,有时需要在盘中实时监控同花顺自选股的数量,以便灵活地自定义提醒、捕捉买卖时点等。那么,如何使用python获取同花顺自选股数据呢?

tzzqn2008的专栏 3675

多线程技术模拟并行计算之二:数组前缀和(Prefix Sum)

一、前缀和(Prefix Sum)定义: 给定一个数组A[1..n],前缀和数组PrefixSum[1..n]定义为:PrefixSum[i] = A[0]+A[1]+...+A[i-1]; 例如:A[5,6,7,8] --> PrefixSum[5,11,18,26] PrefixSum[0] =A[0] ; PrefixSum[1] =A[0] + A[1] ; Prefix...

懂幸福,爱生活 9565

给跨代引用记一本账:Java GC 的分配路径、卡表写屏障与收集器版图快速回顾

本文把 Java GC 的零散名词串成一条推理链路:从 TLAB 指针碰撞分配、逃逸分析,到 Eden、Survivor 与晋升的四条路,重点拆解卡表与写屏障如何为老年代指向新生代的引用记账,及 Minor GC 如何只扫脏卡。基于 JDK 8 实测:分散写使 Young GC 停顿涨 10~15 倍,条件卡标记消除卡表伪共享,计数循环让 System.gc 等待 2.7 秒,Survivor 过小使晋升量增加约 400 倍。文末梳理 JDK 8 到 27 的收集器演进、选型路径与排查顺序。

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 17万+
上一篇: 关于专利
下一篇: Linux Shell 正则表达式之 通配符、元字符、转义符使用实例介绍
crazyhacking
博客等级 码龄15年 299粉丝 148原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值