C ++中的大量线程和效率

如何解决C ++中的大量线程和效率

| 我目前已经用C ++编写了一个程序,该程序有时使用300多个线程。在我的程序中,我有一个结构体数组,该数组的长度等于线程数。假设我有400个结构,因此有400个线程。 在for循环的单次迭代中,我将一个函数应用于400个结构中的每个结构,并且此函数在线程中执行。因此,我有400个线程同时运行。 (我正在使用boost线程库)。 我试图给出我的代码的细目分类(不是实际的代码):
struct my_struct{
  // Structure\'s members
};

std::vector<my_struct> my_vec;

void my_fun(my_struct* my_str){
// Operations on my_str
}

int main(){
  std::vector<boost::thread> thr(400);
  for (int k = 0; k < 300; k++){
    for (int i = 0; i < 400; i++){
      thr.at(i) = boost::thread(my_fun,&my_vec.at(i));
      }
    }

    for (int m = 0; m < M; m++){
      thr.at(m).join();
    }
  }
}
我使用的函数需要大量计算,根据上面的代码,我使用了400个线程来进行计算,这完成了300次。有没有更有效的方法来执行此任务?我不确定一次启用这么多线程是否会影响性能。我听说过线程池库,但是不确定是否会为我带来任何好处。任何帮助表示赞赏。 非常感谢你。     

解决方法

除非目标计算机中具有400多个处理器内核,否则产生400个CPU绑定线程绝对没有任何好处。 不可能毫无把握地告诉您如何更好地分配工作负载,而不知道您正在执行哪种计算以及关于哪种数据。 从发布的内容来看,在黑暗中拍摄照片时,第一个方法是使用
N
个线程(请参阅下文),并在其中划分400个对象,以便每个线程负责处理大约
400/N
个对象。每个线程可以循环300次,并且在每次迭代中,它可以处理其分配的每个对象。
N
是任意数字;实际上,我建议尝试使用其他值并比较性能结果。但是,除非您的线程正在执行I / O或其他会浪费时间在非计算操作上的操作,否则
N
不应大于计算机中处理器内核的数量(尝试一下并迅速观察性能下降)。 编辑:根据正在进行的讨论,建议使用对象队列,从中可以轻松弹出每个
N
线程的对象,以准备进行更多工作。队列当然需要是线程安全的。为了获得最佳性能,应实施无锁队列。这里有好纸。应该通过一次完全填充队列,因此只需要线程安全的读取来简化实现。     ,拥有比实际执行引擎(CPU或核心或正在使用的任何东西-我在这里仅称其为CPU)多的线程的唯一有益方法是,是否某些线程实际上正在等待其他资源比那些CPU。 如果线程是CPU绑定的,则理想数量等于可用的CPU数量。如果许多线程正在等待文件I / O或数据库访问,网络流量或OS事件(等等),那么可能有几百个线程可以。但是,就您而言,情况似乎并非如此。 线程池实际上是一种避免在效率相对较低的情况下连续创建和销毁线程的方法。例如,如果启动一个线程需要十秒钟,而每个线程仅完成一秒钟的工作,那么线程池将是理想的选择。 鉴于您可能会将线程数减少到实质上少于四百个(例如大约两个或四个),这反过来又会增加每个线程的工作量,因此可能不需要线程池。但是同样,它取决于线程将要完成的工作量及其启动成本。 为简单起见,我将从非池版本开始,仅考虑在存在严重性能问题时进行更改。否则,您可能会为自己付出额外的工作,而没有真正的好处。 您仍然可以将工作划分为四百个单元,但是最好的方法是简单地将它们排队,并让每个线程在准备好处理一个项目时从队列中取出一个项目。这样,工作可以在CPU之间自动平衡。如果出于某种奇怪的原因,CPU 1的运行速度是其他CPU的两倍,它将自动获得两倍的工作量。 这比您想像的要重要得多,仅因为几乎可以肯定的是,CPU也将做其他事情-它们不太可能完全专注于完成这项工作。     ,对于计算量大的任务,数百个线程听起来像是一个问题。程序可能花费更多时间进行上下文切换而不是处理。尝试使用N个线程(其中N是您计算机中的内核数)并将工作分块成更大的单元。     ,对于计算密集型工作,您将受到拥有的内核数量的限制。因此,建议使用与内核一样多的线程。 将工作划分为您拥有的核心数量,并创建相同数量的线程并运行它。 如果所有工作项都是独立的,则只需将其分成相等大小的组。如果工作项之间存在依赖关系(item1需要item1的结果),那么您需要根据该依赖关系分为一些有意义的事情。     ,在单处理器计算机上,如果您所做的全部是由于上下文切换而导致的计算,则多线程处理的速度可能比单线程处理的速度要慢。 通常,如果某些线程正在等待某些外围设备,则多线程方法可能会为您的应用程序提供一些灵活性。 就您而言-CPU密集型任务-我怀疑多线程方法能否为您的应用程序带来性能。     ,首先,超过最大并发线程数是浪费。 1个具有超线程或SMT的内核,或者任何芯片制造商想要称呼的内核都具有2个或更多并行线程。您必须确定您的内核可以处理多少个并行线程,并将其乘以内核数。不需要做更多的线程。您有400个线程。在任何时候,可能有396人在睡觉。 不必担心高速缓存行对齐,您只需担心\“ locality \”。当您遍历大于L2缓存的数据时,每次内存访问都是从慢速内存访问一直到RAM的访问。如果您旋转小于L2缓存的数据,则所有内存访问都在L2缓存中,这快100倍。另外,如果所有数据访问均为慢速访问,则cpu上的所有执行线程都将停止。 SMT之所以起作用,是因为(通常)一个线程停滞等待ram,因此CPU可以执行另一个线程。如果您做错了足够的事情并使所有线程停止运行,则说明您基本上已经禁用了SMT。您现在没有并发线程。 因此...如果您的数据集大于L2缓存,则需要“剥离地雷”。将计算分为足够小的部分以适合L2缓存。例如,如果您有一个矩阵,则将矩阵划分为n x m个正方形,这些正方形可以放入L2高速缓存中,并让正确的线程数在上面工作。完成剥离后,移至下一个,依此类推。如果正确执行此操作,您的代码可能会快100倍。 增加局部性的另一种方法是缩小数据。使数据尽可能小。数据越小,它在L2缓存中保留的时间就越多。     

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-