multithreading - 为什么我使用 openMP atomic 的并行代码比串行代码花费更长的时间?
问题描述
我的序列代码片段如下所示。
Program main
use omp_lib
Implicit None
Integer :: i, my_id
Real(8) :: t0, t1, t2, t3, a = 0.0d0
!$ t0 = omp_get_wtime()
Call CPU_time(t2)
! ------------------------------------------ !
Do i = 1, 100000000
a = a + Real(i)
End Do
! ------------------------------------------ !
Call CPU_time(t3)
!$ t1 = omp_get_wtime()
! ------------------------------------------ !
Write (*,*) "a = ", a
Write (*,*) "The wall time is ", t1-t0, "s"
Write (*,*) "The CPU time is ", t3-t2, "s"
End Program main
通过使用 omp 指令do
和atomic
,我将串行代码转换为并行代码。但是,并行程序比串行程序慢。我不明白为什么会这样。接下来是我的并行代码片段:
Program main
use omp_lib
Implicit None
Integer, Parameter :: n_threads = 8
Integer :: i, my_id
Real(8) :: t0, t1, t2, t3, a = 0.0d0
!$ t0 = omp_get_wtime()
Call CPU_time(t2)
! ------------------------------------------ !
!$OMP Parallel Num_threads(n_threads) shared(a)
!$OMP Do
Do i = 1, 100000000
!$OMP Atomic
a = a + Real(i)
End Do
!$OMP End Do
!$OMP End Parallel
! ------------------------------------------ !
Call CPU_time(t3)
!$ t1 = omp_get_wtime()
! ------------------------------------------ !
Write (*,*) "a = ", a
Write (*,*) "The wall time is ", t1-t0, "s"
Write (*,*) "The CPU time is ", t3-t2, "s"
End Program main
所以我的问题是为什么我使用 openMP atomic 的并行代码比串行代码花费更长的时间?
解决方案
您atomic
在每次循环迭代中对同一个变量应用一个操作。此外,该变量在这些循环迭代之间具有相互依赖性。自然,与顺序版本相比,这会带来额外的开销(例如,同步、序列化成本和 CPU 周期)。此外,由于线程使其缓存无效,您可能会遇到很多缓存未命中。
此代码是应该使用reduction
变量的典型代码a
(即, !$omp parallel do reduction(+:a))
而不是原子操作。通过归约操作,每个线程将拥有变量的私有副本'a'
,并且在结束时parallel region
,线程将减少他们的副本将变量'a'
(使用'+'
运算符)转换为单个值,该值将传播到'a'
主线程的变量。
您可以在此SO 线程上找到有关 atomic与reduction之间差异的更详细答案。在那个线程中,甚至还有一个代码,它(就像你的一样)它的版本比它的顺序版本慢几个数量级(即慢 20 倍)。在那种情况下,它甚至比你的更糟糕(即 20x Vs 10x)。atomic
推荐阅读
- c# - 为什么 HttpContext.Current 在使用 ConfigureAwait 的 async/await 中不为空
- ruby-on-rails - simple_form 生成的脚手架模板
- bash - PhantomJS:使用 Cloudflare 保护从网站下载文件
- javascript - javascript中的面向对象的表单验证
- android - Android Room 关系 M:N 带注释 @Relation
- c# - ASP.Net MVC 将值传递给没有专用按钮的控制器
- android - 如何为一个项目使用一张卡片,而不是让所有卡片都填充数据库中的最后一项?
- python - 如何将单词转换为 Python 中每个数字之间用逗号分隔的数字
- ubuntu-16.04 - 在 ubuntu-16.04 上安装 odoo-12
- html - 为什么该复选框不适用于导航?