什么是f2py
f2py是一个将fortran或者c程序转化成python可以调用的库的工具,它几乎和numpy同时出现,使用也相对比较方便,因此一直在numpy包中。在早期,f2py起到的作用类似于numba。你可以将程序的主要逻辑交给python处理,把计算交给fortran,这样兼顾了开发效率和运行效率。并且f2py也可以反向使用,即在fortran中调用python,但是这多少给人有脱裤子放屁的感觉。
现在人们很少用它的原因一方面是numpy已经提供了效率极高的库函数,几乎没有什么需要自己重新写。另外利用numba对循环进行加速的效率也几乎和二进制一致,而实现又非常简单,只需加一个装饰器 @jit。尽管numba并不支持python所有的特性,但是我们完全可以把python当做不需要声明变量类型的fortran使用,这样一些功能基本上已经得到numba的支持,因此f2py的使用场合越来越少。
可是在实践当中,如果手动将一些反复调用的计算过程用fortran重写,在效率上还是可以得到显著提升的。这里面主要原因在于两点:(一)fortran程序是要明确接口数据类型的,节省大量开销;julia语言就借鉴了这一点,如果要获得更好的性能,应明确接口数据类型。(二)numba也未必总是可以优化到原生代码的水平。
在linux下安装和使用f2py相对比较简单,但是在windows下即使安装了anaconda还是要做一些后期处理,因此略显麻烦。这篇文章就是简单总结一下最近实践的结果,首先说明如何在windows下安装f2py,然后简单说明说明如何使用f2py,最后给出一些运算效率的评价。
如何安装和配置
首先需要做的预备工作是安装anaconda,其自带f2py。然后需要一个额外的步骤是安装mingw和libpython。打开powershell,输入以下命令,将会安装mingw和libpython。其中mingw自带gfortran编译器。
conda install mingw, libpython
安装完成后还需要将mingw中可执行文件的路径加入到windows系统的path当中。通常mingw会安装在anaconda目录下,打开后进入“bin”目录,将路径复制加入path。加入路径的方式通常为,右键我的电脑,选择“属性”,在“高级属性”中找到“环境变量”的选项,在环境变量中找到“path”变量,在path变量的末尾添加当前路径,记得用分号和其它路径隔开。
然后在powershell中输入f2py.exe,看系统是否可以找到这个命令。
以上的过程在win7或者win10下是一致的,后期编译就用gfortran。如果你安装了intel-fortran或者其它fortran编译器,需要在编译的时候指定他们的名字。
如何使用f2py
使用f2py你需要对fortran有一定的了解。f2py已经停止开发很多年,它只支持fortran90的很少一部分特性,因此对于编译器的要求并不高。目前mingw的64位版本自带的fortran编译器只到4.7,但是绝大部分常用语法都已经实现,完全支持fortran95的标准,并且支持openmp3.5。更新的编译器无非是支持fortran语言的新标准,并不影响使用。
由于fortran是一门在上古时期的已经存在的语言,并且为了兼容、效率等原因,有许多自己的特点,而实际上只是为了和python一起使用,其实并不需要掌握太多细节。这里仅仅举一个例子说明f2py的用法,至于如何学习一个精简版的fortran,在其它地方说明。
例如现在要计算两个实数的加法,安照fortran的做法要首先写一个子过程(subroutine)如下。
subroutine myadd(a,b,c)
implicit none
real*8::a,b
real*8,intent(out)::c
c=a+b
end subroutine
将其放入文件例如名字为“test.f90”中。在fortran中是支持函数的,但是f2py主要是对fortran中的子过程进行处理,使之能够被python所用。紧接着需要用f2py生成一个python可以导入的库文件,输入下面的命令:
f2py.exe -c test.f90 -m test
这里的"-c"和所有的编译器一样,后面跟源文件,"-m"指定产生库的文件名称,这样在你的文件夹下就会产生一个"test.XXX.pyd"的文件。这里的"XXX"是f2py给你添加的一串字符主要是python的版本号和系统信息,例如我的是"test.cp37-win_amd64.pyd",这个名字不需要修改。
紧接着如果要在python中使用该子程序,需要将该库导入如下:
from numpy import *
from test import myadd
c=myadd(1,2)
print(c)
就可以得到下面的结果:
![7285ca198bc1e2217d08c21f0447f0cb.png](https://i-blog.csdnimg.cn/blog_migrate/f3c0fd2492159b3190e02017ff2302ba.jpeg)
可以看到实际使用过程中,myadd更像一个函数而不是子过程,至于为什么是这样,需要对f2py进一步的了解。
性能评价
我用自己的计算项目进行了简单测试,性能的提升主要是来自于一些不必要的开销。像numba实际上是需要一个预编译阶段,会占用一点时间,其次python语言本身的一些开销,例如类型的判断等。因此在计算强度不大时,fortran还是凸显出自己的实力,但是一旦计算量比较大,这些额外的开销就微不足道了。利用fortran的提升优势就不太明显了。我自身的例子是一个复杂度和矩阵乘法一样的程序。当矩阵尺度为1000时,大约有14%的提升,但是达到2000时,有7%的提升。
总结
经过简单的测试和分析,基本上可以肯定的是,如果你对fortran还比较熟悉,利用f2py加速是一个相当不错的选择,它能结合python输入输出的便利和fortran的高效。如果不会fortran的话,还是让这个语言慢慢消失吧!