Pythran简介:
Pythran通过预先编译,将python代码转为C++代码的 后缀为 .so 的文件,从而 在运行时获得更快的运行速度;
安装步骤:
Mac OS系统安装方式:
$> pip install pythran
$> brew install openblas
$> printf '[compiler]\nblas=openblas\ninclude_dirs=/usr/local/opt/openblas/include\nlibrary_dirs=/usr/local/opt/openblas/lib' > ~/.pythranrc
其他系统请点击链接
使用示例:
先编写如下代码
# -*- coding: utf-8 -*-
"""
(C) rgc
All rights reserved
create time '2021/1/26 10:50'
Usage:
"""
def a(b):
"""
主要用来测试 被编译函数可以调用未被编译的函数
注意 此函数入参 不能是 *args 等可变类型,否则编译失败(Varargs not supported)
:param b:
:return:
"""
print('df', b)
# 注意:如下行注释必须存在,声明入参类型,Pythran通过此 进行编译; 注意 函数名不能错误;
# 如下 声明入参 int list 表示 入参类型时list,元素是int类型
# pythran export dprod(int list, int list)
def dprod(l0, l1):
"""
:param l0: 入参类型时list,元素是int类型
:param l1: 入参类型时list,元素是int类型
:return:
"""
a(2)
return sum(x * y for x, y in zip(l0, l1))
# pythran export drop1(int[], int list,str:float dict)
def drop1(l0, l1, _dict):
"""
:param l0: 入参类型为 numpy.array 元素时 int类型
:param l1: 入参类型时list,元素是int类型
:param _dict: 入参类型时 dict, key是str类型,value是 float类型
:return:
"""
a(2)
l1.append(l0[-1])
print(type(l0))
for k, v in _dict.items():
print(k, v)
return l1
命令行中运行如下命令 如果编译通过 会生成 一个 pythran_use.cpython-36m-darwin.so 文件
pythran pythran_use.py
在另一个py文件中 代码如下,运行即可:
# -*- coding: utf-8 -*-
"""
(C) rgc
All rights reserved
create time '2021/1/26 11:04'
Usage:
"""
import numpy as np
# 像正常模块一样导入即可
from pythran_use import drop1
if __name__ == '__main__':
l0 = np.array([1, 2, 3])
print(type(l0))
print(drop1(l0, [4, 5, 6], {'a': float(1), 'b': float(2)}))
函数入参设置:
argument_type = basic_type
| (argument_type+) # this is a tuple 元祖
| argument_type list # this is a list 列表
| argument_type set # this is a set 集合
| argument_type []+ # this is a ndarray, C-style 是个ndarray
| argument_type [::]+ # this is a strided ndarray
| argument_type [:,...,:]+ # this is a ndarray, Cython style
| argument_type [:,...,3]+ # this is a ndarray, some dimension fixed
| argument_type:argument_type dict # this is a dictionary 是个字典
basic_type = bool | byte | int | float | str | None | slice
| uint8 | uint16 | uint32 | uint64 | uintp
| int8 | int16 | int32 | int64 | intp
| float32 | float64 | float128
| complex64 | complex128 | complex256
具体用法(如上示例代码):
- 如一个 函数 入参 为 numpy.ndarray 每个元素类型为 float; 如果数据结构是 矩阵(或二维数组) 用 float[:, :] 如果数据结果是 列表(或一维数组)用 float[:] 或 float[]
- 如一个 函数 入参 为 int 类型,则 入参 声明为: int
- 如一个函数 入参 为 list 类型,每个元素为 int类型 则入参 声明为: int list
- 如一个函数 入参 为 dict 类型,key为str类型,value为 int类型 则入参 声明为: str:int dict
使用限制:
- 对 dict的 values()方法 调用失败; 但是 可以使用 items()方法;
- 对 numpy和scipy的部分方法 无法预编译,会报错; 如 numpy.reshape, numpy.ndarray的 操作如 "array[b <= a, :]" 和 scipy的fmin_slsqp
- 被编译py文件内 如果有函数 如 func_a 未 添加注释 编译声明( # pythran export func_a()), 则 其他模块文件中无法导入此函数,因为此函数未在 被编译后的 .so文件中;
- 注意 对 numpy,scipy 及python内置的 各种可以预编译的方法 都在 pythran/tables.py文件的 MODULES 属性中,请自行查看; 如果 MODULES中存在对应方法,但是编译 报 没有对应属性 的错误,说明是自己的问题,可以进行修复,否则 就放弃用此包吧; 如下图
总结:
- 每次代码改变时 需要从新编译一次
- Pythran的预编译 和 Numba的运行时编译正好相反; Numba第一次运行时进行编译,所以会较慢; 而Pythran将编译放在了 代码运行前;
- Numba 在numpy的大数据量的for循环时 比较特长;
- NumExpr 在涉及到 一堆的数学计算时比较特长,但是支持的numpy函数较少;
- Pythran 则适用于 大众情况,且对numpy的函数支持比NumExpr多一些,更适用于 list,dict 等的数据处理 及 numpy操作;
- 具体 使用 Pythran预编译后的性能 如何,需要结合实际代码及数据量使用 timeit等工具进行测评;
- 此包使用时的 坑点很多,使用时需要耐心试错,且 国内 相关参考资料较少;
相关链接:
https://pythran.readthedocs.io/en/latest/MANUAL.html#advanced-usage