Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/wix/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Concurrency 用Fortran中的随机数生成器进行并行计算有没有一种简单的方法?_Concurrency_Fortran_Gfortran - Fatal编程技术网

Concurrency 用Fortran中的随机数生成器进行并行计算有没有一种简单的方法?

Concurrency 用Fortran中的随机数生成器进行并行计算有没有一种简单的方法?,concurrency,fortran,gfortran,Concurrency,Fortran,Gfortran,我有一些用Fortran 95编写的有限元代码,我对其进行了优化,这样我现在就可以得到超过16Mil的代码。在2GB内存占用下工作的元素 我的代码的源函数不是平滑的,所以我使用(分层)蒙特卡罗方法进行积分,这需要一个随机数生成器来选择样本位置 我曾尝试使用gfortran-9编译,使用-fopenmp-Ofast-ftree parallelize loops=4,但使用随机数生成器的循环无法并行。我尝试了并发,但显然没有成功,因为随机数不是“纯的”。 我还试图阻止我的循环,但也没有成功 这是我

我有一些用Fortran 95编写的有限元代码,我对其进行了优化,这样我现在就可以得到超过16Mil的代码。在2GB内存占用下工作的元素

我的代码的源函数不是平滑的,所以我使用(分层)蒙特卡罗方法进行积分,这需要一个随机数生成器来选择样本位置

我曾尝试使用gfortran-9编译,使用
-fopenmp-Ofast-ftree parallelize loops=4
,但使用随机数生成器的循环无法并行。我尝试了并发,但显然没有成功,因为随机数不是“纯的”。 我还试图阻止我的循环,但也没有成功

这是我所说的代码

        do  k=1,n_els ! total elements is n_els**2. This is block
            do i=1+ (k-1)*n_els ,k*n_els
                supp_vec = 0 
                integ_vec = 0.0_wp

                ! in this subroutine I call random_number
                call do_element(ind, n_els, i, num_points_per_strat, &
                                strat_rows, strat_cols, supp_vec, integ_vec) 
                do j=1, 4
                    sc_vec(supp_vec(j) ) = integ_vec(j)
                end do
                ! give some info about progress

                if (mod( i , (n_els**2)/10) == 0) print*, i*10/((n_els**2)/10), "% done"
            end do
        end do
似乎我可以将块写入文件并调用例程的不同实例。我想一定有更干净的方法。有什么建议可以让它更快地运行吗


我正在考虑先将一个值为点的块(取决于内存限制)写入一个数组,并在子例程调用中提供它。在我尝试之前,我想我会看看是否有人对更好的方法有什么建议。在可能的情况下,最好保持内存占用率较低

从版本7和更新版本开始,GFortran有一个并行随机数生成器。在实现它时,我使用以下OpenMP代码来验证性能是否确实随线程数的增加而增加(从):


关于“…随机数生成器…”我不知道Fortran或它的库,但在大多数编程语言中,任何事情都有不止一种方法。如果您正在使用的随机数生成器不能满足您的需要(例如,因为不同的线程无法使用它的不同实例),请找到另一个可以工作的随机数生成器。在最坏的情况下,您可能必须自己编写,但我猜不会这样。请使用tag for all.Fortran问题获得更多信息attention@SolomonSlow是的,谢谢。这似乎不像人们想象的那么难:@VladimirF ok感谢tipThat URL简单地指出,当使用并行随机数生成器改变线程数时,将不可能再现结果。@tim18:对于旧设计,确实不可能,因为线程调度是不确定的。有了电流,这是可能的。好吧,这个答案让我很高兴我问了。我将不得不做一些进一步的测试,因为出于某种原因,它仍然无法并行,但谢谢。出于某种原因,我仍然无法让它工作。如果我从循环中的子例程中调用random,这有关系吗?@Notachance:它“应该”工作。也就是说,您问题中的代码示例没有任何OpenMP指令,因此,除非它们出现在您未显示的某段代码中,否则您将只有一个线程处于活动状态。

! Benchmark generating random numbers
! Janne Blomqvist 2015
program randbench
#ifdef _OPENMP
  use omp_lib
#endif
  implicit none
  integer, parameter :: dp=kind(0.d0)          ! double precision
  integer, parameter :: i64 = selected_int_kind(18) ! At least 64-bit integer

#ifdef _OPENMP
  print *, "Using up to ", omp_get_max_threads(), " threads."
#endif
  call genr4
  call genr8
contains
  subroutine genr4
    integer, parameter :: n = int(1e7)
    real, save :: r(n)
    integer :: i
    integer(i64) :: t1, t2, td
#ifdef _OPENMP
    integer :: blocks, blocksize, l, h
#endif
    Print *, "Generate default real random variables"
    call system_clock (t1)
    !$omp parallel do private(i)
    do i = 1, n
       call random_number(r(i))
    end do
    !$omp end parallel do
    call system_clock (t2)
    td = t2 - t1
    print *, "Generating ", n, " default reals individually took ", td, " ticks."
    call system_clock (t1)
#ifdef _OPENMP
    blocks = omp_get_max_threads()
    blocksize = n / blocks
    !$omp parallel do private(l,h,i)
    do i = 0, blocks - 1
       l = i * blocksize + 1
       h = l + blocksize - 1
       !print *, "Low: ", l, " High: ", h
       call random_number(r(l:h))
    end do
#else
    call random_number(r)
#endif
    Call system_clock (t2)
    print *, "Generating ", n, " default reals as an array took  ", t2-t1, &
         " ticks. => ind/arr = ", real(td, dp) / (t2-t1)
  end subroutine genr4

  subroutine genr8
    integer, parameter :: n = int(1e7)
    real(dp), save :: r(n)
    integer :: i
    integer(i64) :: t1, t2, td
#ifdef _OPENMP
    integer :: blocks, blocksize, l, h
#endif
    print *, "Generate double real random variables"
    call system_clock (t1)
    !$omp parallel do
    do i = 1, n
       call random_number(r(i))
    end do
    call system_clock (t2)
    td = t2 - t1
    print *, "Generating ", n, " double reals individually took  ", td, " ticks."
    call system_clock (t1)
#ifdef _OPENMP
    blocks = omp_get_max_threads()
    blocksize = n / blocks
    !$omp parallel do private(l,h,i)
    do i = 0, blocks - 1
       l = i * blocksize + 1
       h = l + blocksize - 1
       !print *, "Low: ", l, " High: ", h
       call random_number(r(l:h))
    end do
#else
    call random_number(r)
#endif
    call system_clock (t2)
    print *, "Generating ", n, " double reals as an array took   ", t2-t1, &
         " ticks. => ind/arr = ", real(td, dp) / (t2 -t1)
  end subroutine genr8

end program