我刚刚用F2PY将一个fortran90子例程打包到python中。这里的精妙之处在于Fortran子例程aslo将python回调函数作为其参数之一:
SUBROUTINE f90foo(pyfunc, a)
real(kind=8),intent(in) :: a
!f2py intent(callback) pyfunc
external pyfunc
!f2py real*8 y,x
!f2py y = pyfunc(x)
!*** debug begins***
print *, 'Start Loop'
do i=1,1000
p = pyfunc(a)
end do
total = etime(elapsed)
print *, 'End: total=', total, ' user=', elapsed(1), ' system=', elapsed(2)
stop
!*** debug ends ***
pyfunc
是在我的python代码中定义的一个python函数。包装器工作得很好,但是运行上面的包装版本,我得到的运行时间大约是纯python的5倍,如下所示
所以,问题是,管理费用是怎么来的?我真的想让pyfunc
保持原样,因为将其重新编码为纯fortran函数非常耗时,那么有没有任何方法可以提高包装器模块的速度?在
在您发布的代码中,
a
是双精度浮点。将它从Fortran传递到Python意味着将Fortran double包装到PyFloat对象,这确实有代价。在纯Python版本中,k是一个PyFloat,您不必为包装它1000次而付出代价。在另一个问题是函数调用本身。从C调用Python函数在性能上已经很差,但是从Fortran调用它们就更糟糕了,因为有一个额外的代码层可以将Fortran函数调用约定(关于堆栈等)转换为C函数调用约定。从C调用Python函数时,需要将参数准备为Python对象,一般创建PyTuple对象作为Python函数的*args参数,在模块表中查找得到函数指针。。。在
最后但并非最不重要的一点:在Fortran和Numpy之间传递2D数组时,需要注意数组的顺序。F2py和numpy在这方面可能很聪明,但是如果Python代码不是按照Fortran顺序来操作数组的,那么性能就会受到影响。在
我不知道pyfunc要做什么,但是如果它与您发布的内容很接近,那么用Python编写循环并只调用一次函数将节省您的时间。如果需要中间值(
p
),让Python函数返回一个包含所有中间值的Numpy数组。在相关问题 更多 >
编程相关推荐