使用OpenMP填充数组元素

huangapple go评论88阅读模式
英文:

Use of OpenMP in filling the array elements

问题

  1. 程序测试
  2. !$ 使用 omp_lib
  3. 隐式无
  4. !$ 调用 omp_set_num_threads(4)
  5. 整数 :: i, j
  6. 整数, 参数 :: dimen = 5
  7. 实数 (kind = 8), 维度(dimen, dimen) :: tstarr = 0.0
  8. !.....................................................................
  9. ! 后面我将以相同的方式填充以下矩阵的元素
  10. ! 实数 (kind = 8), 维度(:,:), 可分配 :: tstarr2
  11. ! 分配(tstarr2(2 * dimen, 2 * dimen))
  12. !.....................................................................
  13. !$ omp 并行执行 默认(共享) 私有(i,j)
  14. do i = 1, dimen
  15. tstarr(i,i) = 3
  16. end do
  17. do i = 1, dimen - 1
  18. tstarr(i + 1, i) = 2
  19. tstarr(i, i + 1) = 2
  20. end do
  21. do i = 1, dimen - 2
  22. tstarr(i + 2, i) = 4
  23. tstarr(i, i + 2) = 4
  24. end do
  25. do i = 1, dimen - 3
  26. tstarr(i + 3, i) = 5
  27. tstarr(i, i + 3) = 5
  28. end do
  29. !$ omp 结束并行执行
  30. do i = 1, dimen
  31. do j = 1, dimen
  32. print *, tstarr(i,j)
  33. end do
  34. end do
  35. end program test

Note: The code you provided seems to be a Fortran program with OpenMP directives for parallelization. The translation above retains the code structure and comments while providing Chinese translations for the keywords and variable types.

英文:
  1. Program test
  2. !$ use omp_lib
  3. implicit none
  4. !$ call omp_set_num_threads(4)
  5. integer :: i, j
  6. integer, parameter :: dimen = 5
  7. real (kind = 8), dimension(dimen, dimen) :: tstarr = 0.0
  8. !.....................................................................
  9. ! Later I will have to fill the elements of the following matrix in the same way
  10. ! real (kind = 8), dimension(:,:), allocatable :: tstarr2
  11. ! allocate(tstarr2(2 * dimen, 2 * dimen))
  12. !.....................................................................
  13. !$ omp parallel do default(shared) private(i,j)
  14. do i = 1, dimen
  15. tstarr(i,i) = 3
  16. end do
  17. do i = 1, dimen - 1
  18. tstarr(i + 1, i) = 2
  19. tstarr(i, i + 1) = 2
  20. end do
  21. do i = 1, dimen - 2
  22. tstarr(i + 2, i) = 4
  23. tstarr(i, i + 2) = 4
  24. end do
  25. do i = 1, dimen - 3
  26. tstarr(i + 3, i) = 5
  27. tstarr(i, i + 3) = 5
  28. end do
  29. !$ omp end parallel do
  30. do i = 1, dimen
  31. do j = 1, dimen
  32. print *, tstarr(i,j)
  33. end do
  34. end do
  35. end program test

This code is working when compiling serially that means with gfortran test.f90 but giving errors when compiling with gfortran -fopenmp test.f90

答案1

得分: 1

"parallel do"指令用于单个"do"循环。您的编译错误表明在此指令中不能有多个循环。

因此,我会使用外部的"parallel",然后为每个循环使用"do"。

英文:

The directive parallel do is used for a single do loop. Your compile error indicates that you can not have multiple loops in this directive.

So I would use an outer parallel and then do for each loop.

答案2

得分: 1

你的代码存在一些问题:

  1. 在Fortran中,你不能将可执行语句(例如call omp_set_num_threads(4))与变量声明混合在一起。实际上,这可能是导致大多数(未报告的)错误的原因。

  2. 不要使用kind = 8。它不是可移植的,不一定得到编译器支持,也可能不会按照你的期望工作。我建议学习有关Fortran种类,并查看下面的代码以获得更好的方法,还要了解如何处理常数。

  3. 你误用了omp parallel do。实际上,我建议你永远不要使用这种构造,我认为它对于语言初学者来说是一个重要的困惑源,并且事实上,它被包含在OMP中是一个错误。为什么我这么认为呢?因为并行化通过OpenMP有两个阶段很重要。首先,你使用!$omp parallel创建(非主线程)线程。第二阶段是使用工作共享构造(如!$omp do)将工作分配给线程。你正在使用的方法混淆了这两者,并模糊了这个重要的分离,根据我的经验,这会导致混淆,从而产生不正确和低效的代码。我强烈建议你在代码中始终分离这两个阶段,就像我下面所做的那样。

我还建议在并行区域中使用default(none)来限定变量的作用范围,这会迫使你考虑变量是应该共享还是私有,同时避免使用call omp_set_num_threads,而是使用环境变量OMP_NUM_THREADS,因为这样你可以在无需重新编译的情况下更改线程数。

修复这些问题后,我得到了以下代码,我认为可以满足你的需求:

  1. Program test
  2. Use iso_fortran_env, Only : wp => real64, stdout => output_unit
  3. !$ use omp_lib
  4. Implicit None
  5. Integer :: i
  6. Integer, Parameter :: dimen = 5
  7. ! 注意
  8. ! 1) Kind = 8 不是可移植的,不应该使用
  9. ! 2) 实数常量默认是单精度,除非另有规定
  10. Real (kind = wp), Dimension(dimen, dimen) :: tstarr = 0.0_wp
  11. !.....................................................................
  12. ! 以后我将以相同的方式填充以下矩阵的元素
  13. ! real (kind = wp), dimension(:,:), allocatable :: tstarr2
  14. ! allocate(tstarr2(2 * dimen, 2 * dimen))
  15. !.....................................................................
  16. ! 注意,在Fortran中,不可将可执行语句与声明混合
  17. ! 但是我不会这样做 - 使用环境变量OMP_NUM_THREADS,您无需重新编译即可更改线程数。因此,我已将其注释掉。
  18. !!!$ call omp_set_num_threads(4)
  19. ! 首先创建线程。我还强烈建议使用default( none )
  20. !$omp parallel default( none ) shared( tstarr ) private( i )
  21. ! 报告我们使用了多少线程
  22. !$omp single
  23. !$ Write( stdout, '( "Using ", i0, " threads" )' ) omp_get_num_threads()
  24. !$omp end single
  25. ! 现在将工作分配给每个循环
  26. !$omp do
  27. Do i = 1, dimen
  28. tstarr(i,i) = 3.0_wp
  29. End Do
  30. !$omp end do
  31. !$omp do
  32. Do i = 1, dimen - 1
  33. tstarr(i + 1, i) = 2.0_wp
  34. tstarr(i, i + 1) = 2.0_wp
  35. End Do
  36. !$omp end do
  37. !$omp do
  38. Do i = 1, dimen - 2
  39. tstarr(i + 2, i) = 4.0_wp
  40. tstarr(i, i + 2) = 4.0_wp
  41. End Do
  42. !$omp end do
  43. !$omp do
  44. Do i = 1, dimen - 3
  45. tstarr(i + 3, i) = 5.0_wp
  46. tstarr(i, i + 3) = 5.0_wp
  47. End Do
  48. !$omp end do
  49. ! 结束并行区域
  50. !$omp end parallel
  51. ! 以漂亮的方式报告矩阵
  52. Do i = 1, dimen
  53. Write( stdout, '( *( f3.1, 2x ) )' ) tstarr(i,:)
  54. End Do
  55. End Program test

希望这可以帮助你解决问题。

英文:

You have a number of problems with your code:

  1. In Fortran you can't mix executable statements such as call omp_set_num_threads(4) with the variable declarations. Actually this is probably the cause of most of your (unreported) errors

  2. Don't use kind = 8. It is not portable, not required to be supported by your compiler, and may not do what you expect. I suggest learning about Fortran kinds, and see the code below for a better way - and also how you should deal with constants.

  3. You are misusing omp parallel do. In fact I suggest you never use this construct, I think it is a major source of confusion for beginners in the language, and in fact a mistake it is included in OMP at all. Why do I think this? Well it is important to understand that there are two stages when parallelizing via OpenMP. First you create the (non-master) threads with !$omp parallel. The second stage is to divide the work up between the threads with a worksharing construct such as !$omp do. The method you are using conflates the two, and blurs this important separation which in my experience leads to confusion and hence incorrect and inefficient code. I strongly recommend you always separate the two stages in your code - as I have done below.

I would also recommend you use default( none ) for scoping variables in the parallel region, it forces you to think about whether a variable should be shared or private, and also to avoid call omp_set_num_threads and use the environment variable OMP_NUM_THREADS instead, as you can then change the number of threads without having to recompile.

Fixing these leads me to the following code, which I think does what you want:

  1. ijb@ijb-Latitude-5410:~/work/stack$ cat omp.f90
  2. Program test
  3. Use iso_fortran_env, Only : wp => real64, stdout => output_unit
  4. !$ use omp_lib
  5. Implicit None
  6. Integer :: i
  7. Integer, Parameter :: dimen = 5
  8. ! Note
  9. ! 1) Kind = 8 is not portable and should not be used
  10. ! 2) Real constants are single precision unless otherwise specified
  11. Real (kind = wp), Dimension(dimen, dimen) :: tstarr = 0.0_wp
  12. !.....................................................................
  13. ! Later I will have to fill the elements of the following matrix in the same way
  14. ! real (kind = wp), dimension(:,:), allocatable :: tstarr2
  15. ! allocate(tstarr2(2 * dimen, 2 * dimen))
  16. !.....................................................................
  17. ! Note in Fortran executable statements can not be mixed with declarations
  18. ! However I wouldn't do it this way - use the environment variable OMP_NUM_THREADS, you don't have
  19. ! to recompile just to change the number of threads. Hence I have commented it out.
  20. !!!$ call omp_set_num_threads(4)
  21. ! First create the threads. I also strongly recommend default( none )
  22. !$omp parallel default( none ) shared( tstarr ) private( i )
  23. ! Report how many threads we are using
  24. !$omp single
  25. !$ Write( stdout, '( "Using ", i0, " threads" )' ) omp_get_num_threads()
  26. !$omp end single
  27. ! Now share out the work for each loop
  28. !$omp do
  29. Do i = 1, dimen
  30. tstarr(i,i) = 3.0_wp
  31. End Do
  32. !$omp end do
  33. !$omp do
  34. Do i = 1, dimen - 1
  35. tstarr(i + 1, i) = 2.0_wp
  36. tstarr(i, i + 1) = 2.0_wp
  37. End Do
  38. !$omp end do
  39. !$omp do
  40. Do i = 1, dimen - 2
  41. tstarr(i + 2, i) = 4.0_wp
  42. tstarr(i, i + 2) = 4.0_wp
  43. End Do
  44. !$omp end do
  45. !$omp do
  46. Do i = 1, dimen - 3
  47. tstarr(i + 3, i) = 5.0_wp
  48. tstarr(i, i + 3) = 5.0_wp
  49. End Do
  50. !$omp end do
  51. ! And end the parallel region
  52. !$omp end parallel
  53. ! Report the matrix - prettily
  54. Do i = 1, dimen
  55. Write( stdout, '( *( f3.1, 2x ) )' ) tstarr(i,:)
  56. End Do
  57. End Program test
  58. ijb@ijb-Latitude-5410:~/work/stack$ gfortran-12 --version
  59. GNU Fortran (GCC) 12.2.0
  60. Copyright © 2022 Free Software Foundation, Inc.
  61. This is free software; see the source for copying conditions. There is NO
  62. warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  63. ijb@ijb-Latitude-5410:~/work/stack$ gfortran-12 -fopenmp -Wall -Wextra -fcheck=all -std=f2018 -Werror -g omp.f90
  64. ijb@ijb-Latitude-5410:~/work/stack$ export OMP_NUM_THREADS=4
  65. ijb@ijb-Latitude-5410:~/work/stack$ ./a.out
  66. Using 4 threads
  67. 3.0 2.0 4.0 5.0 0.0
  68. 2.0 3.0 2.0 4.0 5.0
  69. 4.0 2.0 3.0 2.0 4.0
  70. 5.0 4.0 2.0 3.0 2.0
  71. 0.0 5.0 4.0 2.0 3.0
  72. ijb@ijb-Latitude-5410:~/work/stack$ ./a.out
  73. Using 4 threads
  74. 3.0 2.0 4.0 5.0 0.0
  75. 2.0 3.0 2.0 4.0 5.0
  76. 4.0 2.0 3.0 2.0 4.0
  77. 5.0 4.0 2.0 3.0 2.0
  78. 0.0 5.0 4.0 2.0 3.0
  79. ijb@ijb-Latitude-5410:~/work/stack$ export OMP_NUM_THREADS=12
  80. ijb@ijb-Latitude-5410:~/work/stack$ ./a.out
  81. Using 12 threads
  82. 3.0 2.0 4.0 5.0 0.0
  83. 2.0 3.0 2.0 4.0 5.0
  84. 4.0 2.0 3.0 2.0 4.0
  85. 5.0 4.0 2.0 3.0 2.0
  86. 0.0 5.0 4.0 2.0 3.0
  87. ijb@ijb-Latitude-5410:~/work/stack$ ./a.out
  88. Using 12 threads
  89. 3.0 2.0 4.0 5.0 0.0
  90. 2.0 3.0 2.0 4.0 5.0
  91. 4.0 2.0 3.0 2.0 4.0
  92. 5.0 4.0 2.0 3.0 2.0
  93. 0.0 5.0 4.0 2.0 3.0
  94. ijb@ijb-Latitude-5410:~/work/stack$ ./a.out
  95. Using 12 threads
  96. 3.0 2.0 4.0 5.0 0.0
  97. 2.0 3.0 2.0 4.0 5.0
  98. 4.0 2.0 3.0 2.0 4.0
  99. 5.0 4.0 2.0 3.0 2.0
  100. 0.0 5.0 4.0 2.0 3.0
  101. ijb@ijb-Latitude-5410:~/work/stack$

huangapple
  • 本文由 发表于 2023年7月17日 18:10:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76703419.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定