多线程中对 vector进行大量emplace_back操作,速度下降?

hymwgk 2019-08-01 04:32:24
请给位帮我看看问题在哪,我尽量把问题简单描述
使用设备:VS2015 relase 64 18核36线程CPU

背景: 我有一个多嵌套的for循环,最内层的for循环里面涉及到查unorder_multimap表,整体下来计算量很大,我使用单线程处理的时候,发现整体的处理速度很慢,因为我的电脑核心多,想用多线程将外层for循环分为几块一起计算。
检查发现,时间大多花费在把查出的数据存放在一个vector容器上。

运行结果: 多线程和单线程得出的结果相同且正确,但是速度变得更慢了
下面是简要的代码示意



经过查找,发现问题出现在内层for循环中的查表函数中,查出的数据添加在indices容器的末尾,如果屏蔽掉黄框中的emplace语句,就会加快处理速度。下面是查表函数,仅有三句话


我把indices.emplace中的数据换成常数,如下图,发现仍然很慢,变化不大

疑问: 为什么对vector进行大量emplace操作,在多线程的时候,会使得子线程速度比单线程情况下慢?子线程中对这个容器indices的读写量很大,不懂为什么在多线程中它的速度就降低了很多… 菜鸟求轻拍

...全文
2910 47 打赏 收藏 转发到动态 举报
写回复
用AI写文章
47 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
既然你每个线程处理的数据都是独立的,而且每次都是从vector尾部添加,可以直接用数组,不需要用vector、list之类的。
玉生香 2019-08-06
  • 打赏
  • 举报
回复
频繁插入,会不会要重新分配内存。
竞天问 2019-08-06
  • 打赏
  • 举报
回复
引用 41 楼 super_admi 的回复:
虽然看不懂你们在说些什么,但感觉很厉害的样子。

我比较支持pair内存分配导致多线程速度降低的说法。建议试试vector中存放pair的指针试试?看看瓶颈点会不会转移?


跟pair没关系吧
首先,单线程也是pair
其次,pair其实就是struct{int first, second;};,这能引起什么速度问题?
hymwgk 2019-08-06
  • 打赏
  • 举报
回复
引用 54 楼 super_admi 的回复:
我觉得,你认为这是编译器的问题,这个结论有些武断。
可是,我不用pair的时候,换成常数压进去,问题依旧,可以参考我在stackoverflow上的代码,里面没有用到pair的
super_admi 2019-08-06
  • 打赏
  • 举报
回复
我觉得,你认为这是编译器的问题,这个结论有些武断。
super_admi 2019-08-06
  • 打赏
  • 举报
回复
这里的重点不是vector的内存分配,而是pair的内存分配吧?

引用 50 楼 hymwgk 的回复:
引用 44 楼 玉生香 的回复:
频繁插入,会不会要重新分配内存。
谢谢 我提前reserve了容器内存,还是慢,现在基本确定是编译器的锅,换了版本,基本正常了
hymwgk 2019-08-06
  • 打赏
  • 举报
回复
经过测试,在我们实验室其他i7四核心八线程上装有2015社区版Visual studio的电脑上测试,发现单线程速度仍然大大快于多线程序速度, 我使用的电脑的vs升级到2017之后,万万没有想到是编译器的锅,速度得到改善,单多线程压80万次数据,速度基本一致,测试代码链接为 http://coliru.stacked-crooked.com/a/ac6511016bf5d29a 感谢各位前辈出谋划策,谢谢大家帮助!
lyangucas92 2019-08-06
  • 打赏
  • 举报
回复
沙发,这个问题好牛呀
hymwgk 2019-08-06
  • 打赏
  • 举报
回复
引用 44 楼 玉生香 的回复:
频繁插入,会不会要重新分配内存。
谢谢 我提前reserve了容器内存,还是慢,现在基本确定是编译器的锅,换了版本,基本正常了
hymwgk 2019-08-06
  • 打赏
  • 举报
回复
引用 45 楼 早打大打打核战争 的回复:
既然你每个线程处理的数据都是独立的,而且每次都是从vector尾部添加,可以直接用数组,不需要用vector、list之类的。
因为我存放的数量其实是不确定的,用内置数组觉得很有可能会溢出或者浪费,80万个数据只是我预估的数量写demo测试的,目前基本确定是编译器的锅了,vs2015社区版换成vs2017之后表现稳定,单多基本上速度一致
hymwgk 2019-08-06
  • 打赏
  • 举报
回复
引用 47 楼 走好每一步 的回复:
比方说vector原本申请的内存100字节用完了,插入时,比方stL源码额外加步长20来扩展,那还需要拷贝时间呢。

你在stl的基础上研究算法做啥,先自己写这些数据结构,跑一跑比较好。

据说,不太严谨,涉及这种操作的数据结构,很多人不敢用stl,怕坑!都是自己写。
谢谢~ 我预估了大致的数量,用reserve提前分配了足够大的空间,但是速度还是很慢,不过不过好在,目前换了编译器版本之后,单多线程的速度基本一致了,应该和源码没有关系,估计是编译器的锅,一会我测试完之后放出结果,就会结帖啦
走好每一步 2019-08-06
  • 打赏
  • 举报
回复
比方说vector原本申请的内存100字节用完了,插入时,比方stL源码额外加步长20来扩展,那还需要拷贝时间呢。

你在stl的基础上研究算法做啥,先自己写这些数据结构,跑一跑比较好。

据说,不太严谨,涉及这种操作的数据结构,很多人不敢用stl,怕坑!都是自己写。
走好每一步 2019-08-06
  • 打赏
  • 举报
回复
引用 28 楼 hymwgk 的回复:
[quote=引用 26 楼 srhouyu 的回复:][quote=引用 23 楼 hymwgk 的回复:] [quote=引用 19 楼 srhouyu 的回复:] [quote=引用 17 楼 hymwgk 的回复:]
估计就是因为你的vector里面的pair构造起来比较慢。直接换俩vector<size_t>试试。 而且使用了多线程后,emplace数量是否真的被线程分了?每个线程的工作量真的减少了?你得好好看一下。[/quote] 嗯嗯 谢谢帮助 我写了个小demo专门把vector list 拉出来多线程测试,发现问题依旧,具体的小demo和结果放在了21楼 并行分析工具的结果和之前大程序中的结果基本一致,难道是stl底层的库中出现的问题么[/quote] 不要让线程数超过物理核心数。也不要让每个线程都分配80万数据。例如你有8个线程,那么每个线程应该是10万数据才对。 如果每线程10万×8线程,仍然跑不过每线程80万×单线程,那瓶颈就在于内存读写。你计算量很小,大部分操作都是在随机、跳跃地进行内存访问。如果你每emplace一个元素之前,都加上一顿复杂数学计算,比如算个MD5或者算个圆周率,那么估计多线程的表现一定会好于单线程。[/quote]嗯嗯 我的代码其实在for前会有一系列的矩阵运算,for后也会对读出的容器里面的值进行矩阵运算,计算量还是有的,最新的实验是,我将容器提前进行resize固定,然后用下标修改值,速度就和单线程一致了,如果是内存的访问费时间,为什么单线程或者线程少的时候速度却快呢?难道是多cpu核心把"内存条带宽满了"或"抢先内存总线"什么的?可是这种情况下,是cpu一直参与么,感觉cpu不是该把指令发过去然后在等待就好了么?可“执行”占比一直是高比例的,说明cpu一直在“算”什么东西吧? 我对这个底层的原理一知半解的,我还在查这边的资料。这里我就是瞎猜,其实也是想记录一下思路,说得多,前辈不要见怪哈~ 我现在想从vector源码找找思路,看到底为什么这样子[/quote] 容器这么大规模频率插入,内存扩展不做优化,速度肯定慢的。 申请内存从用户操作切到内核操作,多线程申请内存需要竞争的,不然还不乱套了。 用户到内核切换需要花时间,申请内存竞争,多线程肯定慢了。 多核的优势在于利用cpu的计算能力,如果你没有抓住这个重点,合理榨取硬件性能。 单纯认为多线程就能多快好省是一种误区。
super_admi 2019-08-05
  • 打赏
  • 举报
回复
虽然看不懂你们在说些什么,但感觉很厉害的样子。

我比较支持pair内存分配导致多线程速度降低的说法。建议试试vector中存放pair的指针试试?看看瓶颈点会不会转移?
足球中国 2019-08-05
  • 打赏
  • 举报
回复
一般处理并发,都是读多线程,写是单线程。
amaxiaopang 2019-08-04
  • 打赏
  • 举报
回复
我是来学习的,各位大神谢谢了
srhouyu 2019-08-04
  • 打赏
  • 举报
回复
引用 37 楼 hymwgk 的回复:
我在VS2019上跑的结果,4核8线程机器,x86 Release: Single Thread time: 0.009000 Thread ID 19128 ,time: 0.003000 Thread ID 10536 ,time: 0.003000 Thread ID 20080 ,time: 0.003000 Thread ID 14196 ,time: 0.003000 Thread ID 14092 ,time: 0.004000 Thread ID 17120 ,time: 0.003000 Thread ID 18724 ,time: 0.004000 Thread ID 18984 ,time: 0.003000 Thread ID 16408 ,time: 0.003000 Thread ID 11672 ,time: 0.003000 Thread ID 9096 ,time: 0.006000 Thread ID 9552 ,time: 0.005000 Thread ID 3208 ,time: 0.005000 Thread ID 18020 ,time: 0.005000 Thread ID 17884 ,time: 0.005000 Thread ID 17796 ,time: 0.014000 Thread ID 18000 ,time: 0.009000 x64 Release: Single Thread time: 0.007000 Thread ID 14448 ,time: 0.003000 Thread ID 3220 ,time: 0.003000 Thread ID 7224 ,time: 0.003000 Thread ID 5668 ,time: 0.003000 Thread ID 14776 ,time: 0.003000 Thread ID 7656 ,time: 0.003000 Thread ID 1960 ,time: 0.004000 Thread ID 18700 ,time: 0.006000 Thread ID 14856 ,time: 0.004000 Thread ID 7808 ,time: 0.007000 Thread ID 8076 ,time: 0.006000 Thread ID 14888 ,time: 0.004000 Thread ID 11996 ,time: 0.005000 Thread ID 11920 ,time: 0.008000 Thread ID 20380 ,time: 0.006000 Thread ID 9784 ,time: 0.006000 Thread ID 9160 ,time: 0.006000 都是默认O2优化,并不需要PGO。优化选项在这里:
hymwgk 2019-08-04
  • 打赏
  • 举报
回复
引用 19 楼 srhouyu 的回复:
[quote=引用 17 楼 hymwgk 的回复:]
估计就是因为你的vector里面的pair构造起来比较慢。直接换俩vector<size_t>试试。 而且使用了多线程后,emplace数量是否真的被线程分了?每个线程的工作量真的减少了?你得好好看一下。[/quote] 前辈 我在stack overflow上也问了问,他们有人在vc2017上得到的结果,多线程跑的结果和单线程的速度差不多,这是不是说明是编译器有问题,他开了代码优化,但是我的vs2015 社区版本好像没有PGO选项,总是报错,下面链接分别是1.Stack Overflow问题链接 2.有个外国人跑的结果 http://stackoverflow.com/questions/57343773/why-does-vector-emplace-back-behave-much-slower-in-multiple-threads-than-singl?noredirect=1#comment101179356_57343773 http://coliru.stacked-crooked.com/a/ac6511016bf5d29a
weixin_45465140 2019-08-04
  • 打赏
  • 举报
回复
加油!什么鬼恢复,怎么写不上去。
hymwgk 2019-08-04
  • 打赏
  • 举报
回复
https://stackoverflow.com/questions/57343773/why-does-vector-emplace-back-behave-much-slower-in-multiple-threads-than-singl 啊 英文捉急,stack overflow上问题都描述不清楚...
加载更多回复(28)

65,170

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

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