使用OpenMP填充数组元素

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

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

你的代码存在一些问题:

  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,因为这样你可以在无需重新编译的情况下更改线程数。

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

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:

  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:

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$ 

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:

确定