英文:
Use of OpenMP in filling the array elements
问题
程序测试
!$ 使用 omp_lib
隐式无
!$ 调用 omp_set_num_threads(4)
整数 :: i, j
整数, 参数 :: dimen = 5
实数 (kind = 8), 维度(dimen, dimen) :: tstarr = 0.0
!.....................................................................
! 后面我将以相同的方式填充以下矩阵的元素
! 实数 (kind = 8), 维度(:,:), 可分配 :: tstarr2
! 分配(tstarr2(2 * dimen, 2 * dimen))
!.....................................................................
!$ omp 并行执行 默认(共享) 私有(i,j)
do i = 1, dimen
tstarr(i,i) = 3
end do
do i = 1, dimen - 1
tstarr(i + 1, i) = 2
tstarr(i, i + 1) = 2
end do
do i = 1, dimen - 2
tstarr(i + 2, i) = 4
tstarr(i, i + 2) = 4
end do
do i = 1, dimen - 3
tstarr(i + 3, i) = 5
tstarr(i, i + 3) = 5
end do
!$ omp 结束并行执行
do i = 1, dimen
do j = 1, dimen
print *, tstarr(i,j)
end do
end do
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.
英文:
Program test
!$ use omp_lib
implicit none
!$ call omp_set_num_threads(4)
integer :: i, j
integer, parameter :: dimen = 5
real (kind = 8), dimension(dimen, dimen) :: tstarr = 0.0
!.....................................................................
! Later I will have to fill the elements of the following matrix in the same way
! real (kind = 8), dimension(:,:), allocatable :: tstarr2
! allocate(tstarr2(2 * dimen, 2 * dimen))
!.....................................................................
!$ omp parallel do default(shared) private(i,j)
do i = 1, dimen
tstarr(i,i) = 3
end do
do i = 1, dimen - 1
tstarr(i + 1, i) = 2
tstarr(i, i + 1) = 2
end do
do i = 1, dimen - 2
tstarr(i + 2, i) = 4
tstarr(i, i + 2) = 4
end do
do i = 1, dimen - 3
tstarr(i + 3, i) = 5
tstarr(i, i + 3) = 5
end do
!$ omp end parallel do
do i = 1, dimen
do j = 1, dimen
print *, tstarr(i,j)
end do
end do
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
你的代码存在一些问题:
-
在Fortran中,你不能将可执行语句(例如
call omp_set_num_threads(4)
)与变量声明混合在一起。实际上,这可能是导致大多数(未报告的)错误的原因。 -
不要使用
kind = 8
。它不是可移植的,不一定得到编译器支持,也可能不会按照你的期望工作。我建议学习有关Fortran种类,并查看下面的代码以获得更好的方法,还要了解如何处理常数。 -
你误用了
omp parallel do
。实际上,我建议你永远不要使用这种构造,我认为它对于语言初学者来说是一个重要的困惑源,并且事实上,它被包含在OMP中是一个错误。为什么我这么认为呢?因为并行化通过OpenMP有两个阶段很重要。首先,你使用!$omp parallel
创建(非主线程)线程。第二阶段是使用工作共享构造(如!$omp do
)将工作分配给线程。你正在使用的方法混淆了这两者,并模糊了这个重要的分离,根据我的经验,这会导致混淆,从而产生不正确和低效的代码。我强烈建议你在代码中始终分离这两个阶段,就像我下面所做的那样。
我还建议在并行区域中使用default(none)
来限定变量的作用范围,这会迫使你考虑变量是应该共享还是私有,同时避免使用call omp_set_num_threads
,而是使用环境变量OMP_NUM_THREADS
,因为这样你可以在无需重新编译的情况下更改线程数。
修复这些问题后,我得到了以下代码,我认为可以满足你的需求:
Program test
Use iso_fortran_env, Only : wp => real64, stdout => output_unit
!$ use omp_lib
Implicit None
Integer :: i
Integer, Parameter :: dimen = 5
! 注意
! 1) Kind = 8 不是可移植的,不应该使用
! 2) 实数常量默认是单精度,除非另有规定
Real (kind = wp), Dimension(dimen, dimen) :: tstarr = 0.0_wp
!.....................................................................
! 以后我将以相同的方式填充以下矩阵的元素
! real (kind = wp), dimension(:,:), allocatable :: tstarr2
! allocate(tstarr2(2 * dimen, 2 * dimen))
!.....................................................................
! 注意,在Fortran中,不可将可执行语句与声明混合
! 但是我不会这样做 - 使用环境变量OMP_NUM_THREADS,您无需重新编译即可更改线程数。因此,我已将其注释掉。
!!!$ call omp_set_num_threads(4)
! 首先创建线程。我还强烈建议使用default( none )
!$omp parallel default( none ) shared( tstarr ) private( i )
! 报告我们使用了多少线程
!$omp single
!$ Write( stdout, '( "Using ", i0, " threads" )' ) omp_get_num_threads()
!$omp end single
! 现在将工作分配给每个循环
!$omp do
Do i = 1, dimen
tstarr(i,i) = 3.0_wp
End Do
!$omp end do
!$omp do
Do i = 1, dimen - 1
tstarr(i + 1, i) = 2.0_wp
tstarr(i, i + 1) = 2.0_wp
End Do
!$omp end do
!$omp do
Do i = 1, dimen - 2
tstarr(i + 2, i) = 4.0_wp
tstarr(i, i + 2) = 4.0_wp
End Do
!$omp end do
!$omp do
Do i = 1, dimen - 3
tstarr(i + 3, i) = 5.0_wp
tstarr(i, i + 3) = 5.0_wp
End Do
!$omp end do
! 结束并行区域
!$omp end parallel
! 以漂亮的方式报告矩阵
Do i = 1, dimen
Write( stdout, '( *( f3.1, 2x ) )' ) tstarr(i,:)
End Do
End Program test
希望这可以帮助你解决问题。
英文:
You have a number of problems with your code:
-
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 -
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. -
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:
ijb@ijb-Latitude-5410:~/work/stack$ cat omp.f90
Program test
Use iso_fortran_env, Only : wp => real64, stdout => output_unit
!$ use omp_lib
Implicit None
Integer :: i
Integer, Parameter :: dimen = 5
! Note
! 1) Kind = 8 is not portable and should not be used
! 2) Real constants are single precision unless otherwise specified
Real (kind = wp), Dimension(dimen, dimen) :: tstarr = 0.0_wp
!.....................................................................
! Later I will have to fill the elements of the following matrix in the same way
! real (kind = wp), dimension(:,:), allocatable :: tstarr2
! allocate(tstarr2(2 * dimen, 2 * dimen))
!.....................................................................
! Note in Fortran executable statements can not be mixed with declarations
! However I wouldn't do it this way - use the environment variable OMP_NUM_THREADS, you don't have
! to recompile just to change the number of threads. Hence I have commented it out.
!!!$ call omp_set_num_threads(4)
! First create the threads. I also strongly recommend default( none )
!$omp parallel default( none ) shared( tstarr ) private( i )
! Report how many threads we are using
!$omp single
!$ Write( stdout, '( "Using ", i0, " threads" )' ) omp_get_num_threads()
!$omp end single
! Now share out the work for each loop
!$omp do
Do i = 1, dimen
tstarr(i,i) = 3.0_wp
End Do
!$omp end do
!$omp do
Do i = 1, dimen - 1
tstarr(i + 1, i) = 2.0_wp
tstarr(i, i + 1) = 2.0_wp
End Do
!$omp end do
!$omp do
Do i = 1, dimen - 2
tstarr(i + 2, i) = 4.0_wp
tstarr(i, i + 2) = 4.0_wp
End Do
!$omp end do
!$omp do
Do i = 1, dimen - 3
tstarr(i + 3, i) = 5.0_wp
tstarr(i, i + 3) = 5.0_wp
End Do
!$omp end do
! And end the parallel region
!$omp end parallel
! Report the matrix - prettily
Do i = 1, dimen
Write( stdout, '( *( f3.1, 2x ) )' ) tstarr(i,:)
End Do
End Program test
ijb@ijb-Latitude-5410:~/work/stack$ gfortran-12 --version
GNU Fortran (GCC) 12.2.0
Copyright © 2022 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
ijb@ijb-Latitude-5410:~/work/stack$ gfortran-12 -fopenmp -Wall -Wextra -fcheck=all -std=f2018 -Werror -g omp.f90
ijb@ijb-Latitude-5410:~/work/stack$ export OMP_NUM_THREADS=4
ijb@ijb-Latitude-5410:~/work/stack$ ./a.out
Using 4 threads
3.0 2.0 4.0 5.0 0.0
2.0 3.0 2.0 4.0 5.0
4.0 2.0 3.0 2.0 4.0
5.0 4.0 2.0 3.0 2.0
0.0 5.0 4.0 2.0 3.0
ijb@ijb-Latitude-5410:~/work/stack$ ./a.out
Using 4 threads
3.0 2.0 4.0 5.0 0.0
2.0 3.0 2.0 4.0 5.0
4.0 2.0 3.0 2.0 4.0
5.0 4.0 2.0 3.0 2.0
0.0 5.0 4.0 2.0 3.0
ijb@ijb-Latitude-5410:~/work/stack$ export OMP_NUM_THREADS=12
ijb@ijb-Latitude-5410:~/work/stack$ ./a.out
Using 12 threads
3.0 2.0 4.0 5.0 0.0
2.0 3.0 2.0 4.0 5.0
4.0 2.0 3.0 2.0 4.0
5.0 4.0 2.0 3.0 2.0
0.0 5.0 4.0 2.0 3.0
ijb@ijb-Latitude-5410:~/work/stack$ ./a.out
Using 12 threads
3.0 2.0 4.0 5.0 0.0
2.0 3.0 2.0 4.0 5.0
4.0 2.0 3.0 2.0 4.0
5.0 4.0 2.0 3.0 2.0
0.0 5.0 4.0 2.0 3.0
ijb@ijb-Latitude-5410:~/work/stack$ ./a.out
Using 12 threads
3.0 2.0 4.0 5.0 0.0
2.0 3.0 2.0 4.0 5.0
4.0 2.0 3.0 2.0 4.0
5.0 4.0 2.0 3.0 2.0
0.0 5.0 4.0 2.0 3.0
ijb@ijb-Latitude-5410:~/work/stack$
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论