在多线程里要做到的真正的平行计算简直不可能

assassin5616 2012-02-23 05:02:22
加精
最近折腾了很久一个关于平行计算的程序,我测试的机器算比较牛的了,16个核,内存16个G。当然,我程序只能用4G。

我要做的不过是启动四个或者8个线程同时运行一个相同的算法。线程间就我写的部分肯定没有任何资源需要共享,也就是说线程间没有任何互斥。 结果跑起来的结果让我大跌眼镜,启动4个线程的时候,同样的算法,时间比只有一个线程比起来多了差不多50%,8个线程的时候,直接翻倍还要多。

这个时候我唯一能想到的就是内存这个东西了各个线程是需要竞争的了,于是我替换了intel 的tbb::scalable_alloc(有点像广告),结果好了一点点,也就是好了10%的样子。

我的算法里面new 和 delete这些有一些,但是在现代程序里面绝对算是正常的。

我大刀阔斧地简化了我的算法,发现只有当简化到一定程度时,使用tbb::scalable_alloc的优势才体现出来,基本可以实现跑8个线程和跑1个线程时时间一样。但是算法一旦复杂,包括程序的结构(链接多个动态库什么的),tbb基本上就没什么优势了。

如果我不用多线程,直接用多进程,比如启动8个进程,执行时间和只有一个进程运行时一模一样(这个倒是不奇怪,16个核在哪呢,可不是来打酱油的)。

我现在真的很好奇到底是什么东西影响了多线程的运行效率,互斥我是可以保证没有的。分配内存的问题按道理tbb::scalable_alloc可以解决,至少程序够简单的时候是解决了的。难道最终还是内存分配问题影响了线程的效率? 还有没有其他的东西会影响呢?

另外就是,如果执行算法的时间如果长,比如需要十秒左右,这个时候跑8个线程和跑1个线程的执行时间就完全一样了。这也是为什么我敢保证线程之间肯定没有互斥的原因,如果有的话, 不管执行多长时间,8个线程的时间都不会和1个线程一样。

哪位对多核运算厉害的牛人能解答一下我遇到的这些神秘现象呢?三跪九叩首了




...全文
2381 67 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
67 条回复
切换为时间正序
请发表友善的回复…
发表回复
dotmonkey 2012-03-07
  • 打赏
  • 举报
回复
觉得有可能是cache miss导致。
pgmsoul 2012-03-07
  • 打赏
  • 举报
回复
提供一个思路吧,多线程导致效率下降,而多进程没有。那么原因无非就是线程间产生了交集,这交集如果不在变量上,那么就在系统级的调用上,比如分配和释放内存,而且这是两个非常耗时的操作。

但是长时间的运行又没有这个问题,可见系统还是能够优化这种现象,不过10S级就能体现出来,还有必要优化吗?难道是频繁的启动的小任务?
assassin5616 2012-03-07
  • 打赏
  • 举报
回复
[Quote=引用 63 楼 intel_zhenyuwang 的回复:]
可以用VTune(TM) Amplifier XE中的 Concurrency Analysis去分析每个线程的消耗(Elapsed Time),及并行性(还有时间线报告),及热点函数、热点行的CPI (Cycles per instruction, 均值)。关注CPI偏高的代码,可以深入到汇编代码,看是不是Load动作耗时过多 - 相关于内存访问。这样比盲人摸象好。

童鞋们的发言很好。我做……
[/Quote]
第4点这个东西怎么避免呢?不同的线程都同时分配内存的话,地址肯定是不同的啊?
intel_zhenyuwang 2012-03-06
  • 打赏
  • 举报
回复
可以用VTune(TM) Amplifier XE中的 Concurrency Analysis去分析每个线程的消耗(Elapsed Time),及并行性(还有时间线报告),及热点函数、热点行的CPI (Cycles per instruction, 均值)。关注CPI偏高的代码,可以深入到汇编代码,看是不是Load动作耗时过多 - 相关于内存访问。这样比盲人摸象好。

童鞋们的发言很好。我做一些补充:

1. 如线程间无互斥,应该没有等待的时间。
2. 每个线程可能是在各CPU轮转的,如有Hyper-Threading,不如关掉。二个Logic CPU共享一个物理CPU,会有线程间资源共享(因为有内核已足够多)。
3. 使用TBB的 allocator固然好,最好地址返回(Store)到local variable
4. 如果不同的线程访问不同的内存,如0x???10000, 0x???20000...可能会导致缓存更换过快,影响性能。

由于没有具体代码,暂时说这些。
yswddd 2012-03-06
  • 打赏
  • 举报
回复
确实不错,值得学习!
Dalek 2012-03-05
  • 打赏
  • 举报
回复
相同功能的线程并行建议使用线程池进行管理
liuliufen 2012-03-05
  • 打赏
  • 举报
回复
STL这个东西我一直都不是很熟悉,也用的不好,原来也做过这方面的改进的,确实能提高不少运行时间;

估计楼主的就是用了些很强大的库之类的,节省了代码,牺牲了性能;
YHL27 2012-03-05
  • 打赏
  • 举报
回复
厉害。。。
liuliufen 2012-03-04
  • 打赏
  • 举报
回复
there must be some mistakes
waq12 2012-03-04
  • 打赏
  • 举报
回复
之前刚好碰到过类似的疑问,不过我感觉解决之道还是需要对具体问题进行更加详细的性能分析。我的经验是在并行性方面线程几乎不劣与进程!
feixiang992 2012-03-03
  • 打赏
  • 举报
回复
内存预先申请好,不要多次申请、释放
ruguicheng 2012-03-02
  • 打赏
  • 举报
回复
[Quote=引用 52 楼 bingouqd 的回复:]
引用 10 楼 assassin5616 的回复:
引用 2 楼 ckc 的回复:
内存预先申请好,不要多次申请、释放

这个说起来挺容易的,但是真正写代码的时候,比如说实现真正的一些软件开发的时候,能做到把所有内存都预先申请好吗? 特别是像程序里面还要经常使用stl的很多container之类的

多次重复使用的内容,可以预先申请好的。 用一次就不用了的 就不必这么复杂了。。。
[/Quote]对对
dfasri 2012-03-02
  • 打赏
  • 举报
回复
想要高效就别用STL了. STL简直就是效率的杀手
hlfkyo 2012-03-02
  • 打赏
  • 举报
回复
我以前也做过类似的试验,和楼主的结果差不多
bingouqd 2012-03-02
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 assassin5616 的回复:]
引用 2 楼 ckc 的回复:
内存预先申请好,不要多次申请、释放

这个说起来挺容易的,但是真正写代码的时候,比如说实现真正的一些软件开发的时候,能做到把所有内存都预先申请好吗? 特别是像程序里面还要经常使用stl的很多container之类的
[/Quote]
多次重复使用的内容,可以预先申请好的。 用一次就不用了的 就不必这么复杂了。。。
fly_in_wind_ 2012-03-02
  • 打赏
  • 举报
回复
[Quote=引用 45 楼 assassin5616 的回复:]

引用 43 楼 fly_in_wind_ 的回复:
工作中我也干过多线程优化的尝试,

和楼主的结论不同,在我的尝试中,多线程的优势是非常明显的,加速系数能达到0.7的样子(打个比方说一个线程的时候处理能力是1000条/秒,那么5个线程的时候系统的处理能力就能提升到3500条/秒)

我想,也许楼主可以从下面来考虑问题 :
1.是否可以在多线程启动好以前把所有的资源先申请好?
2.……
[/Quote]


跑了很久都能维持这个效果。

你的性能loss可能是STL反复分配释放小块内存了。建议放弃STL试试看
超级大笨狼 2012-03-02
  • 打赏
  • 举报
回复
分合付出的代价,要远远小于子任务,才有意义.
rogyl 2012-02-29
  • 打赏
  • 举报
回复
一、如何测时,在linux还是windows?
二、程序瓶颈在那里。

并行不是想用就能用的
sandunfandeshijie 2012-02-29
  • 打赏
  • 举报
回复
看一下你每一个任务分配量是否均衡 并行计算中load balance 很重要。
csdn网速很慢 2012-02-29
  • 打赏
  • 举报
回复
如果我不用多线程,直接用多进程,比如启动8个进程,执行时间和只有一个进程运行时一模一样(这个倒是不奇怪,16个核在哪呢,可不是来打酱油的)。

这个为什么一样呢。 按理说多线程只是cpu的功能。内存只能串行传输数据8个线程或进程内存浪费的时间得翻8倍时间为什么会一样呢? 是不是计时有问题
加载更多回复(37)

567

社区成员

发帖
与我相关
我的任务
社区描述
英特尔® 边缘计算,聚焦于边缘计算、AI、IoT等领域,为开发者提供丰富的开发资源、创新技术、解决方案与行业活动。
社区管理员
  • 英特尔技术社区
  • shere_lin
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧