最近一直在研究自己的Fortran程序的运行效率,查阅了一些资料和做了大量的程序测试,总结如下:
程序编写方面:
1.Module的使用:尽可能多使用
某些数组以及变量值要重复用到,比如有多个子程序需要调用,存在两种情况:
(1)值已知,这种情况下单个变量值较常见,比如圆周率π,就用parameter声明在Module中;
real,parameter::pi=3.1415926
(2)值未知,这种情况下数组较常见,比如定义一个数组,用Module声明变量,封装在主程序前,然后在主程序中use Module,然后计算变量或者数组元素的值,这些值就会作为全局变量一直存在该数组或者变量中。要注意:在Module中不能实现分配动态数组功能。
Module Model1
integer::n1(8),n2(8),n3(8),Tn1(8)
end Module
program main
use Model1
n1(0)=0
call grid(L, D, n1, n2, n3)
forall(i=0:7)
Tn1(i+1)=sum(n1(0:i+1))
end forall
实践证明,使用Module模块真的大大提高了程序的运行效率。
2.数组方面:高效访问数组
(1)连续地访问整个数组或是大部分数组时, 其访问速度是最快的。尽量在最少的数组操作下访问全部数组或其主要部分, 而避免在不同数组单元上分散地多次操作。当读或写一个数组时, 尽量使用数组名, 而避免使用指定每个单元的do 循环。Fortran 90 的数组语法允许在表达式中使用其名字以引用整个数组,使用效率最高。例如:
REAL::A (100 ,100)
A = 0.0
A=A+1 ! 以1 递增所有数组单元
(2)尽量正确引用多维数组并使其按以列为主自然升序排列以提高数组使用效率。在以列为主的自然升序排列下, 最左边的下标变化最快。多维数组在内存中按列排列,先列后行,先低维再高维。
如循环:
do i=1,3
do j=1,5
sum=sum+a(i,j)
end do
end do
该数组是按以行为主的顺序访问,访问效率较低,修改一下效率就会大大提高:
do j=1,5
do i=1,3
sum=sum+a(i,j)
end do
end do
3.循环:减少无效循环以及嵌套循环,减少循环次数,能用数组索引代替循环就用索引变化,也就是将do循环向量化;尽可能的使用Forall循环代替do循环。
do i=2,100:
a(i)=b(i)*0.5
c(i)=d(i-2)+e(i)+f(i)
d(i)=c(i-1)+a(i)+f(i)
f(i)=d(i)*2
end do
可以向量化为:
a(2:100)=b(2:100)*0.5
do i=2,100:
c(i)=d(i-2)+e(i)+f(i)
d(i)=c(i-1)+a(i)+e(i)
end do
f(2:100)=d(2:100)*2
进一步还可以向量化为:
a(2:100)=b(2:100)*0.5
f(2:100)=e(2:100)+f(2:100)
a(2:100)=a(2:100)+e(2:100)
do i=2,100:
c(i)=d(i-2)+f(i)
d(i)=c(i-1)+a(i)
end do
f(2:100)=d(2:100)*2
这样做的好处就是提高了循环的效率。
后续更新,以上是基于自己的实践和查阅资料所得,希望有所帮助!有问题欢迎交流!
参考资料:
1.王国鸣. FORTRAN DO循环中某些赋值语句表达式的向量化[J]. 哈尔滨工业大学学报, 1982(4):33-41.
2.向毅斌, 陈敦军. Visual Fortran程序运行速度的优化方法[J]. 微型机与应用, 2000, 19(8):9-10.
3.高效使用Fortran数组https://blog.csdn.net/Fortran/article/details/340294