2.4在运行时选择线程数量
在运行时选择线程数量
C++标准库中对此有所帮助的特性是std::thread::hardware_currency()。这个函数返回一个对于给定程序执行时能够真正并发运行的线程数量的指示。例如,在多核系统上它可能是CPU 核心的数量。它仅仅是一个提示,如果该信息不可用则函数可能会返回0,但它对于在线程间分割任务是一个有用的指南。
清单2.8展示了std::accumulate 的一个简单的并行版本实现。它在线程之间划分所做的工作,使得每个线程具有最小数目的元素以避免过多线程的开销。请注意,该实现假定所有的操作都不引发异常,即便异常可能会发生。例如,std::thread构造函数如果不能启动一个新的执行线程那么它将引发异常。在这样的算法中处理异常超出了这个简单示例的范围。
//std::accumulate的简单的并行版本
#include <thread>
#include <numeric>
#include <algorithm>
#include <functional>
#include <vector>
#include <iostream>template<typename Iterator,typename T>
struct accumulate_block
{void operator()(Iterator first,Iterator last,T& 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)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();unsigned long const num_threads=std::min(hardware_threads!=0?hardware_threads:2,max_threads);unsigned long const block_size=length/num_threads; //❹std::vector<T> results(num_threads);std::vector<std::thread> threads(num_threads-1); //❺Iterator block_start=first;for(unsigned long i=0;i<(num_threads-1);++i){Iterator block_end=block_start;std::advance(block_end,block_size); //❻threads[i]=std::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]); //❾std::for_each(threads.begin(),threads.end(),std::mem_fn(&std::thread::join)); //❿return std::accumulate(results.begin(),results.end(),init); //⓫
} int main()
{std::vector<int> vi;for(int i=0;i<10;++i){vi.push_back(10);}int sum=parallel_accumulate(vi.begin(),vi.end(),5);std::cout<<"sum="<<sum<<std::endl;
}
虽然这是一个相当长的函数,但它实际上是很直观的。如果输入范围为空❶,只返回初始值init。否则,此范围内至少有一个元素,于是你将要处理的元素数量除以最小的块大小,以获取线程的最大数量❷。这是为了避免当范围中只有五个值时,在一个32核的机器上创建32个线程。
要运行的线程数是你计算出的最大值和硬件线程数量❸的较小值。你不会想要运行比硬件所能支持的更多的线程(超额订阅,oversubscription),因为上下文切换将意味着更多的线程会降低性能。如果对std::thread::hardware_concurrency()的调用返回0,你只需简单地替换上你所选择的数量,在这个例子中我选择了2。你不会想要运行过多的线程,因为在单核的机器上这会使事情变慢,但同样地你也不希望运行的过少,因为那样的话,你就会错过可用的并发。
每个待处理的线程的条目数量是范围的长度除以线程的数量❹。如果你担心数量不能整除,没必要——稍后再来处理。
既然你知道有多少个线程,你可以为中间结果创建一个 std::vector<T>
,同时为线程创建一个 std::vector<std::thread>
❺。请注意,你需要启动比
num_threads 少一个的线程,因为已经有一个了。
启动线程是个简单的循环:递进block_end迭代器到当前块的结尾❻,并启动一个新的线程来累计此块的结果❼。下一个块的开始是这一个的结束❽。
当你启动了所有的线程后,这个线程就可以处理最后的块❾。这就是你处理所有未被整除的地方。你知道最后一块的结尾只能是last,无论在那个块里有多少元素。一旦累计出最后一个块的结果,你可以等待所有使用std::for_each 生成的线程❿,如清单2.7中所示,接着通过最后调用std::accumulate将结果累加起来⓫。
在你离开这个例子前,值得指出的是在类型T的加法运算符不满足结合律的地方(如float和 double),这个parallel_accumulate的结果可能会跟std::accumulate的有所出入,这是将范围分组成块导致的。此外,对迭代器的需求要更严格一些,它们必须至少是前向迭代器(forward iterators),然而std::accumulate可以和单通输入迭代器(input iterators)一起工作,同时T必须是可默认构造的(default constructible)以使得你能够创建results向量。这些需求的各种变化是并行算法很常见的:就其本质而言,它们以某种方式的不同是为了使其并行,并且在结果和需求上产生影响。另外值得一提的是,因为你不能直接从一个线程中返回值,所以你必须将相关项的引用传入results向量中。从线程中返回结果的替代方法,会通过使用future来实现。
在这种情况下,每个线程所需的所有信息在线程开始时传入,包括存储其计算结果的位置。实际情况并非总是如此。有时,作为进程的一部分有必要能够以某种方式标识线程。你可以传入一个标识数,如同在清单2.7中 i 的值,但是如果需要此标识符的函数在调用栈中深达数个层次,并且可能从任意线程中被调用,那样做就很不方便。当我们设计C++线程库时就预见到了这方面的需求,所以每个线程都有一个唯一的标识符。
相关文章:

2.4在运行时选择线程数量
在运行时选择线程数量 C标准库中对此有所帮助的特性是std::thread::hardware_currency()。这个函数返回一个对于给定程序执行时能够真正并发运行的线程数量的指示。例如,在多核系统上它可能是CPU 核心的数量。它仅仅是一个提示,如果该信息不可用则函数可…...

element-ui中Notification 通知自定义样式、按钮及点击事件
Notification 通知用于悬浮出现在页面角落,显示全局的通知提醒消息。 一、自定义html页面 element-ui官方文档中说明Notification 通知组件的message 属性支持传入 HTML 片段,但是示例只展示了简单的html片段,通常不能满足开发中的更深入需要…...

无头单向非循环单链表、带头双向循环链表
文章内容 1. 链表的概念及结构 2. 链表的分类 3.链表实现 4.代码 文章目录 1. 链表的概念及结构 概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表 中的指针链接次序实现的 。 现实中 数据结构中 链表和顺序表…...

UE4/5C++多线程插件制作(二十、源码)
目录 头文件 MultiThreadPlugins.uplugin MultiThreadPlugins.Build.cs MultiThreadPlugins.h MTPPlatform.h MTPManage.h RTPAgendy.h MTPThreadTaskManage.h...

构建稳健的PostgreSQL数据库:备份、恢复与灾难恢复策略
在当今数字化时代,数据成为企业最宝贵的资产之一。而数据库是存储、管理和保护这些数据的核心。PostgreSQL,作为一个强大的开源关系型数据库管理系统,被广泛用于各种企业和应用场景。然而,即使使用了最强大的数据库系统࿰…...

查看本地mysql账号密码
使用Navicat工具打开本地mysql,新建查询输入下面查询语句 SELECT user, authentication_string FROM mysql.user WHERE userroot将authentication_string 中的加密密码复制出来打开链接: Magic Data 5输入加密的密码,和验证码,点…...

数据结构:顺序表详解
数据结构:顺序表详解 一、 线性表二、 顺序表概念及结构1. 静态顺序表:使用定长数组存储元素。2. 动态顺序表:使用动态开辟的数组存储。三、接口实现1. 创建2. 初始化3. 扩容4. 打印5. 销毁6. 尾插7. 尾删8. 头插9. 头删10. 插入任意位置数据…...

采集数据筛选-过滤不要数据或只保留指定数据
采集文章数据,有时候会遇到一些不需要采集的数据,或者只想采集一些特定的数据,可以使用简数采集器的内容过滤功能,对采集的数据进行筛选,只有符合的数据才采集保留。 可以用于过滤掉一些广告、专题、网站首页等无效数…...

RISC-V基础指令之shift移动指令slli、srli、srai、sll、srl、sra
RISC-V的shift指令是用于对一个寄存器或一个立即数进行位移运算,并将结果存放在另一个寄存器中的指令。位移运算就是把一个操作数的每一位向左或向右移动一定的位数,得到一个新的位。RISC-V的shift指令有以下几种: slli:左逻辑位…...

【沁恒蓝牙mesh】CH58x flash分区与数据存储管理
本文主要介绍了 沁恒蓝牙芯片 CH58x 的flash 分区与数据存储管理 📋 个人简介 💖 作者简介:大家好,我是喜欢记录零碎知识点的小菜鸟。😎📝 个人主页:欢迎访问我的 Ethernet_Comm 博客主页&…...

Ctfshow web入门 JWT篇 web345-web350 详细题解 全
CTFshow JWT web345 先看题目,提示admin。 抓个包看看看。 好吧我不装了,其实我知道是JWT。直接开做。 在jwt.io转换后,发现不存在第三部分的签证,也就不需要知道密钥。 全称是JSON Web Token。 通俗地说,JWT的本质…...

2023年国家留学基金委(CSC)青年骨干教师项目即将开始申报
国家留学基金委(以下简称CSC)的青年骨干教师出国研修项目(即高校合作项目),将于2023年9月10-25日进行网上报名及申请受理。知识人网小编特提醒申请者注意流程及政策,以防错过申报时间。 青年骨干教师项目&a…...

GC垃圾回收器【入门笔记】
GC:Garbage Collectors 垃圾回收器 C/C,手动回收内存;难调试、门槛高。忘记回收、多次回收等问题 Java、Golang等,有垃圾回收器:自动回收,技术门槛降低 一、如何定位垃圾? https://www.infoq.c…...

在 React 中渲染大型数据集的 3 种方法
随着 Web 应用程序变得越来越复杂,我们需要找到有效的方法来优化性能和渲染大型数据集。在 React 应用程序中处理大型数据集时,一次呈现所有数据可能会导致性能不佳和加载时间变慢。 虚拟化是一种通过一次仅呈现数据集的一部分来解决此问题的技术&#…...

uniapp iOS 消息推送扩展:后台/杀死app进程状态能语音播报
文章目录 引言I 前期准备1.1 配置扩展1.2 测试报文II iOS Extension(扩展)2.1 插件作者配置2.2 插件使用者配置see also引言 HBuilderX3.1.5+版本uni原生插件支持iOS Extension(扩展)。 消息推送离线语音播报插件获取方式: 公z号:iOS逆向: 离线包x10, 源码是x15。 实…...

批量创建可配置物料参数文件
启用可配置物料之后,每次创建新的物料需要通过CU41创建可配置物料,没找大批量创建的程序,所以SHDB录屏搞了一个代码。 前提:物料主数据初始化通过程序导入时,可配置物料参数文件已按照物料代码赋值。 效果…...

性能压力测试的重要性与实施方法
性能压力测试是在软件开发过程中评估系统在不同负载条件下的表现和稳定性的关键步骤。这种测试是为了确定系统在正常和峰值负载下的性能表现,以验证系统是否能够满足用户需求,同时发现潜在的性能问题并加以解决。 首先,性能压力测试对于确保系…...

HCIP入门静态实验
题目及要求 第一步:拓扑的搭建 第二步:路由、IP的配置 r1: <Huawei>sys Enter system view, return user view with CtrlZ. [Huawei]sys r1 [r1]int loop [r1]int LoopBack 0 [r1-LoopBack0]ip add 192.168.1.65 27 [r1-LoopBack0]int loop 1 […...

Vue与js的融合,如何编写现代化的前端应用
随着Web应用的不断发展,前端开发已经成为了当今互联网行业中最为流行和重要的领域之一。而在前端开发中,JavaScript无疑是最为常用和基础的语言之一。而Vue.js作为一种轻量级的JavaScript框架,它的出现极大地简化了前端开发的过程,…...

Boost开发指南-3.10singleton_pool
singleton_pool singleton_pool与 pool的接口完全一致,可以分配简单数据类型(POD)的内存指针,但它是一个单件。 singleton_pool位于名字空间boost,为了使用singleton_pool组件,需要包含头文件<boost/p…...

腾讯云从业者认证考试考点——云网络产品
文章目录 腾讯云网络产品功能网络产品概述负载均衡(Cloud Load Balancer)私有网络(Virtual Private Cloud,VPC)专线接入弹性网卡(多网卡热插拔服务)NAT网关(NAT Gateway)…...

Miniled透明屏:超薄、轻便,还有哪些特点?
Miniled透明屏是一种新型的显示屏技术,它采用了微小的LED灯珠作为显示单元,通过透明的材料进行封装,使得整个屏幕具有透明的特性。Miniled透明屏具有以下几个特点: 首先,Miniled透明屏具有高亮度和高对比度的特点。 由…...

MySQL 极速安装使用与卸载
目录 mysql-5.6.51 极速安装使用与卸载 sqlyog工具 mysql简化 mysql-8.1.0下载配置 再完善 mysql-5.6.51 极速安装使用与卸载 mysql-8.1.0下载安装在后 mysql中国官网 MySQLhttps://www.mysql.com/cn/ 点击MySQL社区服务器 点击历史档案 下载完 解压 用管理员运行cmd&a…...

举个栗子!Tableau 技巧(256):灵活折叠文本表的多级数据行
通常,Tableau 默认的图表分层结构是统一打开或关上,有什么办法可以按需选择展开或折叠?如下示例:单击“”展开层级,单击“-“收起层级。 可以试试集操作!今天的栗子,就来分享具体实现方法吧~ 本…...

Android View 初始化完成后,如果再调用measure再设置点击事件则点击事件会失效的解决方案
比如LinearLayout 或RecyclerView 我们在初始化完成并加载完数据后再次调用measure计算高度再setLayoutParams 会导致后面设置的点击事件失效。 比如: RecyclerView rv_select dialog.findViewById(R.id.rv_select); //点击事件rv_select.setOnItemClickListener(n…...

客户端电脑使用 FTP的Cadence_CIS库方法说明 (下)
简介:随着企业的规模扩大,硬件工程师的增多,使用统一服务器上的库管理,可以减少设计错误,提高效率。 使用在FTP上布局Cadence_CIS库,是目前的主流的做法之一; 本文方法,用于已经配置…...

【ES】笔记-let 声明及其特性
let 声明及其特性 声明变量 变量赋值、也可以批量赋值 let a;let b,c,d;let e100;let f521,giloveyou,h[];变量不能重复声明 let star罗志祥;let star小猪;块级作用域,let声明的变量只在块级作用域内有效 {let girl周杨青;}console.log(girl)注意:在 i…...

wps 预加载项插件本地开发启动项目打开wps 客户端,未看到加载项菜单,
wps 预加载项插件本地开发启动项目打开wps 客户端,未看到加载项菜单,请检查本地c盘安装目录下“jsplugins.xml”信息是否添加成功 如下图 name 插件项目 url 本地插件运行地址及端口 <jsplugins><jspluginonline name"wps-soft-copyright…...

uni-app开发微信小程序经常遇到的一些问题及解决方案
1.如何获取用户信息? 可以使用uni.getUserInfo接口获取用户信息。需要用户授权。 2.如何实现下拉刷新? 可以使用uni-app提供的页面组件内置下拉刷新功能,也可以自定义下拉刷新组件。 3.如何实现上拉加载更多? 可以在页面onReachBo…...

一个 git 仓库下拥有多个项目的 git hooks 配置方案
前言 通常情况下,一个 git 仓库就是一个项目,只需要配置一套 git hooks 脚本就可以执行各种校验任务。对于 monorepo 项目也是如此,monorepo 项目下的多个 packages 之间,它们是有关联的,可以互相引用,所以…...