Fortran Coder

查看: 12693|回复: 4
打印 上一主题 下一主题

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

[复制链接]

9

帖子

5

主题

0

精华

入门

F 币
57 元
贡献
35 点
跳转到指定楼层
楼主
发表于 2021-2-4 18:18:31 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 sam295040799 于 2021-2-10 13:38 编辑

最近发现的一个问题,一直困扰我,看看没有大神给我解惑,有偿。
[Fortran] 纯文本查看 复制代码
01MODULE CDAS1
02 
03 
04  REAL,DIMENSION(:,:,:),ALLOCATABLE,SAVE :: indt,ce,ce1,ce2
05  real dzz
06 
07  ENDMODULE CDAS1
08 
09 
10PROGRAM cs
11 
12 
13USE CDAS1
14 
15 
16IMPLICIT NONE
17 
18 
19  integer i,j,k,n,maxx,maxy,maxz,x1,x2,y1,y2,z1,z2
20  real time1,time2
21 
22 
23  dzz=0.6
24  maxz=80;maxy=80;maxx=80
25  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))
26  indt=0;ce=0
27 x1=10;x2=30              y1=10;y2=40
28 z1=15;z2=35
29 
30 
31      do k=1,maxz
32      do j=1,maxy
33      do i=1,maxx
34      if(i>x1.and.i<x2) indt(i,j,k)=1           
35      if(j>y1.and.j<y2) indt(i,j,k)=1
36      if(k>z1.and.k<z2) indt(i,j,k)=1
37      enddo
38      enddo
39      enddo
40 
41 
42 call CPU_TIME(time1)
43 
44 
45 do n=1,1000
46  do k=1,maxz
47  do j=1,maxy
48  do i=1,maxx
49  if( indt(i,j,k)==1) cycle
50  ce(i,j,k)=ce1(i,j,k)-ce2(i,j-1,k)
51  enddo
52  enddo
53  enddo
54 enddo
55call CPU_TIME(time2)
56print*,'time',time2-time1
57 
58 
59ENDPROGRAM 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零柒玖玖(企鹅)



分享到:  微信微信
收藏收藏 点赞点赞 点踩点踩

250

帖子

2

主题

0

精华

宗师

F 币
1731 元
贡献
872 点

规矩勋章

沙发
发表于 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

9

帖子

5

主题

0

精华

入门

F 币
57 元
贡献
35 点
板凳
 楼主| 发表于 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
我实际上只需要这部分,这部分执行时间和总时间不成比例

838

帖子

2

主题

0

精华

大宗师

F 币
3937 元
贡献
2339 点
地板
发表于 2021-2-10 10:18:13 | 只看该作者
1、如果想要达到时间与计算量成比例,用release,并且关闭优化,因为优化后的程序并不是严格按照代码顺序运行。图中开启优化后时间不到1s,而关闭优化时间接近10s。
2、如果没有if,每次循环只执行一条赋值;有if时,一半的循环只执行赋值,另一半执行判断+cycle,而判断是较为耗时的。因此加了if反而更慢。
3、根据这个代码的实际情况,可以限制循环范围,规避if。
[Fortran] 纯文本查看 复制代码
01indt=0;ce=0
02do k=1,maxz
03do j=1,maxy
04do i=1,39
05indt(i,j,k)=1
06enddo
07do i=40,maxx
08ce(i,j,k)=dzz
09end do
10enddo
11enddo

1.png (51.36 KB, 下载次数: 307)

1.png

2.png (51.64 KB, 下载次数: 292)

2.png

2038

帖子

12

主题

5

精华

论坛跑堂

臭石头雪球

F 币
1676 元
贡献
715 点

美女勋章热心勋章星光勋章新人勋章贡献勋章管理勋章帅哥勋章爱心勋章规矩勋章元老勋章水王勋章

5#
发表于 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代码。
尝试用下面的代码,简练,直观,高效。

[Fortran] 纯文本查看 复制代码
01MODULE CDAS1
02  REAL,DIMENSION(:,:,:),ALLOCATABLE,SAVE :: indt,ce
03  real dzz
04ENDMODULE CDAS1
05 
06PROGRAM cs
07  USE CDAS1
08  IMPLICIT NONE
09  integer maxx,maxy,maxz
10  real time1,time2
11  dzz=0.6
12  maxz=80;maxy=80;maxx=80
13  allocate(indt(maxx,maxy,maxz),ce(maxx,maxy,maxz))
14  indt=0;ce=0
15  indt(:39,:,:)=1
16  call CPU_TIME(time1)
17  where(indt==1) ce=dzz
18  call CPU_TIME(time2)
19  print*,'time',time2-time1
20ENDPROGRAM cs
您需要登录后才可以回帖 登录 | 极速注册

本版积分规则

捐赠本站|Archiver|关于我们 About Us|小黑屋|Fcode ( 京ICP备18005632-2号 )

GMT+8, 2025-4-29 18:03

Powered by Discuz! X3.4

© 2013-2025 Comsenz Inc.

快速回复 返回顶部 返回列表