sam295040799 发表于 2021-2-4 18:18:31

最近发现的一个问题,一直困扰我,看看没有大神给我解惑

本帖最后由 sam295040799 于 2021-2-10 13:38 编辑

最近发现的一个问题,一直困扰我,看看没有大神给我解惑,有偿。
       MODULE CDAS1


      REAL,DIMENSION(:,:,:),ALLOCATABLE,SAVE :: indt,ce,ce1,ce2
      real dzz

      ENDMODULE CDAS1


      PROGRAM cs


      USE CDAS1


      IMPLICIT NONE


      integer i,j,k,n,maxx,maxy,maxz,x1,x2,y1,y2,z1,z2
      real time1,time2


      dzz=0.6
      maxz=80;maxy=80;maxx=80
      allocate(indt(maxx,maxy,maxz),ce(0:maxx,0:maxy,0:maxz),ce1(0:maxx,0:maxy,0:maxz),ce2(0:maxx,0:maxy,0:maxz))
      indt=0;ce=0
       x1=10;x2=30            y1=10;y2=40
       z1=15;z2=35


            do k=1,maxz
            do j=1,maxy
            do i=1,maxx
            if(i>x1.and.i<x2) indt(i,j,k)=1            
            if(j>y1.and.j<y2) indt(i,j,k)=1
            if(k>z1.and.k<z2) indt(i,j,k)=1
            enddo
            enddo
            enddo


       call CPU_TIME(time1)


       do n=1,1000
      do k=1,maxz
      do j=1,maxy
      do i=1,maxx
      if( indt(i,j,k)==1) cycle
      ce(i,j,k)=ce1(i,j,k)-ce2(i,j-1,k)
      enddo
      enddo
      enddo
       enddo
      call CPU_TIME(time2)
      print*,'time',time2-time1


      ENDPROGRAM cs
这段程序在release下执行的,出现下面情况
这段程序里 if( indt(i,j,k)==1) cycle是对所有的i,j,k进行筛选,不满足条件的就进行ce(i,j,k)=dzz,但是结果发现没有if( indt(i,j,k)==1) cycle,ce(i,j,k)=dzz程序执行次数是80*80*80次,而有if( indt(i,j,k)==1) cycle,ce(i,j,k)=dzz程序执行次数,两者执行次数相差很多,但是耗时相差没这么多。
关于这个问题的解释就是,fortran循环是列循环,如果循环没有中断,循环速度很快,但是如果是跳跃循环,那这个循环速度就会变慢,再加上if(indt(i,j,k)==1)cycle,也耗时。但是没有找到好的办法让这个循环里带if()cycle 的代码 执行次数和时间 成比例。如果在debug执行,情况又不一样了



联系方式:二9五零4零柒玖玖(企鹅)



necrohan 发表于 2021-2-6 10:42:21

if( indt(i,j,k)==1)then
ce(i,j,k)=ce(i,j,k)
else
ce(i,j,k)=dzz
endif

sam295040799 发表于 2021-2-6 14:03:49

necrohan 发表于 2021-2-6 10:42
if( indt(i,j,k)==1)then
ce(i,j,k)=ce(i,j,k)
else



if( indt(i,j,k)==1)then
ce(i,j,k)=dzz
endif
我实际上只需要这部分,这部分执行时间和总时间不成比例

li913 发表于 2021-2-10 10:18:13

1、如果想要达到时间与计算量成比例,用release,并且关闭优化,因为优化后的程序并不是严格按照代码顺序运行。图中开启优化后时间不到1s,而关闭优化时间接近10s。
2、如果没有if,每次循环只执行一条赋值;有if时,一半的循环只执行赋值,另一半执行判断+cycle,而判断是较为耗时的。因此加了if反而更慢。
3、根据这个代码的实际情况,可以限制循环范围,规避if。indt=0;ce=0
do k=1,maxz
do j=1,maxy
do i=1,39
indt(i,j,k)=1
enddo
do i=40,maxx
ce(i,j,k)=dzz
end do
enddo
enddo

fcode 发表于 2021-2-10 12:19:08

1. 循环是有损耗的。cycle 也是有损耗的。
2. ce(i,j,k)=dzz 单独一个赋值语句速度是很快的。
3. cycle并不能减少循环的次数,都是80*80*80*1000次。
4. cycle 损耗和赋值语句的损耗相当(差别不大—)。当有 if 的时候,执行 cycle不执行赋值。当没有 if 的时候,执行赋值但不执行cycle。因此,两者的区别也不大。
5. 你的代码写得啰嗦,又低效。你要知道,Fortran是矢量化的语言,它本身可以减少很多不必要的循环,不要用C语言的逻辑来写Fortran代码。
尝试用下面的代码,简练,直观,高效。

MODULE CDAS1
REAL,DIMENSION(:,:,:),ALLOCATABLE,SAVE :: indt,ce
real dzz
ENDMODULE CDAS1

PROGRAM cs
USE CDAS1
IMPLICIT NONE
integer maxx,maxy,maxz
real time1,time2
dzz=0.6
maxz=80;maxy=80;maxx=80
allocate(indt(maxx,maxy,maxz),ce(maxx,maxy,maxz))
indt=0;ce=0
indt(:39,:,:)=1
call CPU_TIME(time1)
where(indt==1) ce=dzz
call CPU_TIME(time2)
print*,'time',time2-time1
ENDPROGRAM cs
页: [1]
查看完整版本: 最近发现的一个问题,一直困扰我,看看没有大神给我解惑