如何加速Maple生成的含大量变量赋值的Python代码?
问题描述
我正在处理的一段用于创建numpy数组的代码包含大量变量赋值操作,该代码由Maple优化生成,对应极其复杂的数学运算,无法通过Maple做进一步简化。
from math import sin, cos import numpy as np def __calc_tau(self, q, s_dot_v, omega_dot_ref, f_th, qm_ddot_ref): SC_param_est = self.SC_param_est SC_param = self.SC_param t1 = SC_param[3] + SC_param_est[0] + SC_param[10] + SC_param[9] + SC_param[8] t2 = cos(q[9]) t3 = sin(q[9]) t4 = SC_param[38] - SC_param[41] t5 = SC_param[35] - SC_param[38] + SC_param[40] t6 = t2 * SC_param_est[7] t7 = t3 * SC_param_est[9] t8 = t5 * SC_param[10] t9 = (-t6 + t4 - t7) * SC_param_est[0] t10 = SC_param[32] * SC_param[9] # 中间省略t11到t637的赋值逻辑 t638 = ... MCQ = np.array([[t1, 0, 0, 0, t37, t54, t54, -t127, t61, -t128, 0, -t126, t125, 0, -t91, -t106, -t106, -t45 * t108 * s_dot_v[6] - t46 * t91, -t114 * t45 - t16 * t46, -(t123 * t45 + t46 * t78) * SC_param_est[0], SC_param[7] * t124 * t1], [0, t1, 0, -t31, 0, -t51, -t51, -t56, -t38, -t68, t126, 0, -t134, t129, 0, t131, t131, t46 * t108 * s_dot_v[6] - t45 * t91, t114 * t46 - t16 * t45, -SC_param_est[0] * (-t123 * t46 + t45 * t78), -t135 * t133 * t1], t86, t34, t36, t35, [t54, -t51, 0, -t300, -t58, t89, t89, t115, t121, -t69, -t106, t131, 0, t450, t43, t55, t55, t170, t76, t239, -t47], t10, t5, t2], dtype='float64')
我使用timeit测试了程序各部分的执行时间,发现该段代码是性能瓶颈,在Intel i7-8565U @ 1.8 GHz处理器上的执行时间约为3ms。请问是否有合适的方案可以对其进行加速?
优化方案
以下是改造成本从低到高的几种可行加速方案:
- Numba JIT编译(优先推荐)
这段代码是纯标量数值运算,没有分支和动态逻辑,非常适合用Numba的即时编译优化。只需要给函数添加@numba.njit(cache=True)装饰器,Numba会将函数编译为机器码执行,通常可以获得10~100倍的性能提升,改造后执行时间可降到几十微秒级别。注意首次调用会有编译开销,开启cache参数后后续调用不需要重复编译。 - 常量预计算
代码中大量t变量的计算仅依赖self.SC_param和self.SC_param_est两个固定属性,不依赖每次调用的输入参数,这部分计算可以提前在类初始化时完成并存储为实例属性,不需要每次调用函数都重复计算,可直接减少20%~50%的运算量。 - 数组构造逻辑优化
现有代码用嵌套列表构造再转numpy数组的方式存在额外的列表内存分配和转换开销。可以提前创建对应形状的空numpy数组,直接对每个下标位置赋值,例如:
可以减少约10%的执行开销。MCQ = np.empty((3, 21), dtype='float64') MCQ[0, 0] = t1 MCQ[0, 1] = 0 # 依次给所有位置赋值 - Cython静态编译
如果不想引入Numba依赖,可以将这段代码改写为Cython代码,给所有变量添加double类型标注,关闭Python动态类型检查,编译为C扩展后执行性能和Numba接近。
内容的提问来源于stack exchange,提问作者msbet
相关产品推荐
相关产品推荐

