C++并发编程之std::partial_sum的并行版本

在C++中,std::partial_sum 是一个用于计算前缀和的算法,它将输入范围中的每个元素替换为其前缀和。为了提高性能,我们可以设计并实现一个并行版本的 std::partial_sum,以便在多核处理器上并行执行前缀和计算。基本思想是将输入范围划分为多个子范围,每个子范围由一个单独的线程处理,并在所有线程完成后进行合并。

基本思想

  1. 任务划分:将输入范围中的元素划分为多个子范围,每个子范围由一个线程处理。
  2. 线程执行:每个线程独立计算其子范围的前缀和。为了确保最终结果的正确性,每个子范围的前缀和计算需要考虑到前一个子范围的最后一个元素的前缀和。
  3. 合并结果:在所有线程完成其任务后,主线程负责合并各个子范围的前缀和结果,确保整个输入范围的前缀和计算是正确的。

实现代码

我们可以使用 C++11 的 std::thread 来实现并行版本的 std::partial_sum。为了简化实现,我们可以使用 std::vector 来管理线程,并使用 std::mutex 来确保对共享数据的访问是线程安全的。

#include <iostream>
#include <vector>
#include <thread>
#include <algorithm>
#include <iterator>
#include <mutex>// 并行版本的 std::partial_sum
template<typename Iterator, typename OutputIterator>
OutputIterator parallel_partial_sum(Iterator first, Iterator last, OutputIterator result) {const unsigned long length = std::distance(first, last);// 如果没有元素,直接返回 resultif (length == 0) {return result;}// 获取系统支持的并发线程数const unsigned long max_threads = std::thread::hardware_concurrency();const unsigned long num_threads = std::min(max_threads != 0 ? max_threads : 2, length);// 每个线程处理的元素数量const unsigned long block_size = length / num_threads;std::vector<std::thread> threads(num_threads - 1);std::vector<typename Iterator::value_type> block_sums(num_threads, 0);std::mutex block_sums_mutex;// 启动线程for (unsigned long i = 0; i < num_threads - 1; ++i) {Iterator block_start = first + i * block_size;Iterator block_end = block_start + block_size;threads[i] = std::thread([block_start, block_end, result, i, &block_sums, &block_sums_mutex, block_size]() {*result = *block_start;typename Iterator::value_type sum = *block_start;for (Iterator it = block_start + 1; it != block_end; ++it) {sum += *it;*++result = sum;}std::lock_guard<std::mutex> lock(block_sums_mutex);block_sums[i] = sum;});}// 主线程处理最后一个块Iterator block_start = first + (num_threads - 1) * block_size;Iterator block_end = last;*result = *block_start;typename Iterator::value_type sum = *block_start;for (Iterator it = block_start + 1; it != block_end; ++it) {sum += *it;*++result = sum;}std::lock_guard<std::mutex> lock(block_sums_mutex);block_sums[num_threads - 1] = sum;// 等待所有线程完成std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join));// 合并结果OutputIterator final_result = result;for (unsigned long i = 1; i < num_threads; ++i) {*final_result += block_sums[i - 1];++final_result;}for (unsigned long i = 1; i < num_threads; ++i) {for (unsigned long j = 1; j < block_size; ++j) {*final_result += block_sums[i - 1];++final_result;}}return result + std::distance(first, last);
}int main() {std::vector<int> input = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};std::vector<int> output(input.size());// 使用并行版本的 std::partial_sumparallel_partial_sum(input.begin(), input.end(), output.begin());// 输出结果for (const auto& value : output) {std::cout << value << " ";}std::cout << std::endl;return 0;
}

代码说明

  1. 任务划分

    • length 是输入范围中的元素总数。
    • max_threads 是系统支持的并发线程数,num_threads 是我们实际使用的线程数(不超过元素数量)。
    • block_size 是每个线程处理的元素数量。
  2. 线程执行

    • 我们创建了一个 std::vector<std::thread> 来存储所有线程。
    • 每个线程独立计算其子范围的前缀和,并将最后一个元素的前缀和存储在 block_sums 中。为了确保 block_sums 的访问是线程安全的,我们使用了 std::mutex
  3. 合并结果

    • 主线程通过 std::thread::join 等待所有子线程完成。
    • 主线程遍历 block_sums,对每个子范围的前缀和进行调整,确保整个输入范围的前缀和计算是正确的。

应用

并行版本的 std::partial_sum 可以用于需要快速计算大规模数据前缀和的场景,例如:

  1. 数值计算

    • 例如,在科学计算中计算累积和、累积乘积等。
  2. 数据处理

    • 例如,在处理时间序列数据时,计算某个时间窗口内的累计值。
  3. 机器学习

    • 例如,在训练模型时,计算某个批次数据的累计损失。

总结

通过实现并行版本的 std::partial_sum,我们可以在多核处理器上并行执行前缀和计算,从而提高程序的性能。代码中展示了如何将输入范围中的元素划分为多个子范围,并使用多个线程分别处理这些子范围。这种技术可以广泛应用于需要高效计算大规模数据前缀和的场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/68249.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机的错误计算(二百一十二)

摘要 利用两个大模型计算 实验表明&#xff0c;两个大模型均进行了中肯的分析。另外&#xff0c;其中一个大模型给出了 Python代码&#xff0c;运行后&#xff0c;结果中有7位错误数字&#xff1b;而一个大模型进行加减运算时出错。 例1. 计算 下面是与一个大模型的对话…

Vue+Echarts+百度地图 实现 路径规划

实现功能: 通过选择 相关调拨&#xff0c;系统自动规划 路径&#xff0c;并且以地图的形式呈现最佳路径 技术难点: 1. vue 结合使用 echarts 2.echarts 在 vue嵌入百度地图&#xff0c;并且做出路径 曲线 最终结果:

【算法】图解两个链表相交的一系列问题

问&#xff1a; 给定两个可能有环也可能无环的单链表&#xff0c;头节点head1和head2。请实现一个函数&#xff0c;如果两个链表相交&#xff0c;请返回相交的第一个节点&#xff1b;如果不相交&#xff0c;返回null。如果两个链表长度之和为N&#xff0c;时间复杂度请达到O(N…

Go-Zero整合Goose实现MySQL数据库版本管理

推荐阅读 【系列好文】go-zero从入门到精通&#xff08;看了就会&#xff09; 教程地址&#xff1a;https://blog.csdn.net/u011019141/article/details/139619172 Go-Zero整合Goose实现MySQL数据库版本管理的教程 在开发中&#xff0c;数据库迁移和版本管理是必不可少的工作。…

JAVA:Spring Boot 集成 JWT 实现身份验证的技术指南

1、简述 在现代Web开发中&#xff0c;安全性尤为重要。为了确保用户的身份&#xff0c;JSON Web Token&#xff08;JWT&#xff09;作为一种轻量级且无状态的身份验证方案&#xff0c;广泛应用于微服务和分布式系统中。本篇博客将讲解如何在Spring Boot 中集成JWT实现身份验证…

说一说mongodb组合索引的匹配规则

一、背景 有一张1000多万条记录的大表&#xff0c;需要做归档至历史表&#xff0c;出现了大量慢查询。 查询条件是 "classroomId": {$in: ["xxx", "xxx", ..... "xxx","xxx", "xxx" ] }耗时近5秒&#xff0c;且…

更新java

下载 Java 下载 |神谕 (oracle.com)

CSS3的aria-hidden学习

前言 aria-hidden 属性可用于隐藏非交互内容&#xff0c;使其在无障碍 API 中不可见。即当aria-hidden"true" 添加到一个元素会将该元素及其所有子元素从无障碍树中移除&#xff0c;这可以通过隐藏来改善辅助技术用户的体验&#xff1a; 纯装饰性内容&#xff0c;如…

【Java设计模式-5】装饰模式:给咖啡加点“佐料”

今天咱们要探索一下Java世界里的装饰模式&#xff08;Decorator Pattern&#xff09;。为了让这个过程更加生动易懂&#xff0c;咱们就以大家都熟悉的咖啡饮品来举例吧&#xff0c;想象一下&#xff0c;你就是那个咖啡大师&#xff0c;要给顾客调制出各种独特口味的咖啡哦&…

C++(5)

1.运算符重载 头文件 #ifndef MYSTRING_H #define MYSTRING_H#include <iostream> #include <cstring>using namespace std;class myString { private:char *str;//C风格字符串int size0; public:std::string s_str;//转换构造函数myString(const std::string &a…

K8S--配置存活、就绪和启动探针

目录 1 本人基础环境2 目的3 存活、就绪和启动探针介绍3.1 存活探针3.2 就绪探针3.3 启动探针 4 探针使用场景4.1 存活探针4.2 就绪探针4.3 启动探针 5 配置存活、就绪和启动探针5.1 定义存活探针5.2 定义一个存活态 HTTP 请求接口5.3 定义 TCP 的就绪探针、存活探测5.4 定义 g…

【HTML+CSS+JS+VUE】web前端教程-36-JavaScript简介

JavaScript介绍 JavaScript是一种轻量级的脚本语言&#xff0c;所谓脚本语言&#xff0c;指的是它不具备开发操作系统的能力&#xff0c;而是用来编写控制其他大型应用程序的“脚本” JavaScript是一种嵌入式语言&#xff0c;它本身提供的核心语法不算很多 为什么学习JavaScri…

LLM实现视频切片合成 前沿知识调研

1.相关产品 产品链接腾讯智影https://zenvideo.qq.com/可灵https://klingai.kuaishou.com/即梦https://jimeng.jianying.com/ai-tool/home/Runwayhttps://aitools.dedao.cn/ai/runwayml-com/Descripthttps://www.descript.com/?utm_sourceai-bot.cn/Opus Cliphttps://www.opu…

AI多模态论文解读:LLaVA-CoT:让视觉语言模型逐步推理

本文作者&#xff1a;AIGCmagic社区 猫先生 一、简 介 LLaVA-CoT引入了四个不同的阶段&#xff08;摘要、标题、推理和结论&#xff09;&#xff0c;使模型能够独立进行系统化的多阶段推理&#xff0c;显著提高了在推理密集型任务上的准确性。 编译了LLaVA-CoT-100k数据集&am…

分布式缓存redis

分布式缓存redis 1 redis单机&#xff08;单节点&#xff09;部署缺点 &#xff08;1&#xff09;数据丢失问题&#xff1a;redis是内存存储&#xff0c;服务重启可能会丢失数据 &#xff08;2&#xff09;并发能力问题&#xff1a;redis单节点&#xff08;单机&#xff09;部…

《C++11》nullptr介绍:从NULL说起

在C11之前&#xff0c;我们通常使用NULL来表示空指针。然而&#xff0c;NULL在C中有一些问题和限制&#xff0c;这就是C11引入nullptr的原因。本文将详细介绍nullptr的定义、用法和优点。 1. NULL的问题 在C中&#xff0c;NULL实际上是一个整数0&#xff0c;而不是一个真正的…

供应链数字化转型参考大型供应链系统技术架构设计方案

该文介绍了一个大型供应链系统技术架构的设计方案&#xff0c;包括整体设计、核心技术目录和应用案例。设计采用Choerodon微服务框架&#xff0c;关注海量并发、可伸缩性、安全性等方面。同时&#xff0c;方案符合大型企业结构的HR组织架构&#xff0c;支持多级组织架构和角色、…

STM32F1学习——DMA直接存储器存取

一、DMA直接存储器存取 DMA的全称是 Direct Memory Access 直接存储器存取&#xff0c;他可以提供外设和存储器间或存储器和存储器间的高速数据传输&#xff0c;无需CPU的干预。 STM32有12个DMA通道&#xff0c;由DMA1(7个通道组成)和DMA2(5个通道组成)&#xff0c;STM32F103C8…

一个使用 Golang 编写的新一代网络爬虫框架,支持JS动态内容爬取

大家好&#xff0c;今天给大家分享一个由ProjectDiscovery组织开发的开源“下一代爬虫框架”Katana&#xff0c;旨在提供高效、灵活且功能丰富的网络爬取体验&#xff0c;适用于各种自动化管道和数据收集任务。 项目介绍 Katana 是 ProjectDiscovery 精心打造的命令行界面&…

6.2 MySQL时间和日期函数

以前我们就用过now()函数来获得系统时间&#xff0c;用datediff()函数来计算日期相差的天数。我们在计算工龄的时候&#xff0c;让两个日期相减。那么其中的这个now函数返回的就是当前的系统日期和时间。 1. 获取系统时间函数 now()函数&#xff0c;返回的这个日期和时间的格…