使用 Cython 最大限度地提高性能
Posted
技术标签:
【中文标题】使用 Cython 最大限度地提高性能【英文标题】:Maximising Performance Increases with Cython 【发布时间】:2012-03-06 12:36:00 【问题描述】:我一直在尝试编写一个图形应用程序来演示大学项目的机器学习,并且我一直在用 Python 开发它。因为 Python 是一种相当慢的语言,我一直在寻找加快运行时执行的方法,结果偶然发现了 Cython。我对 C/C++ 还不是很熟悉,但我已经尝试过尽可能多地静态键入我的代码(尽管警告说这会降低可读性/灵活性;这不是我目前主要关心的问题)。
但是,我并没有真正注意到这个实现与纯 Python 相比有任何显着改进,我想知道是否有人对如何加快它有任何建议。我对 10 倍加速之类的东西非常满意,但我不确定这是否现实。
̶I̶̶h̶a̶v̶e̶n̶'̶t̶̶p̶r̶o̶f̶i̶l̶e̶d̶̶m̶y̶̶c̶o̶d̶e̶̶y̶e̶t̶ 我已经分析了我的代码,结果链接如下。
因为它仍在进行中,所以布局不是很好,但我做了一些简单的功能分组。
源代码可以在here找到。代码中最相关的部分发布在下面。
.
遍历给定pad的内存:
cdef findBestApproximation(int padindex):
cdef double last_collision_x
cdef double last_collision_y
cdef double last_collision_i_angle
cdef double last_collision_i_speed
cdef double last_collision_f_angle
cdef double last_collision_f_speed
cdef double x_divergence
cdef double y_divergenve
cdef double f_angular_divergence
cdef double divergence
printData("FINDING APPROXIMATION FOR PAD %s...\n" % padindex)
pad = Pads.padlist[padindex]
memory = pad.memory
ball = Balls.ball
if not memory:
approximation = getPadMidpoint(padindex)
return approximation
collision_data = getCollisionData()
(last_collision_x, last_collision_y, last_collision_i_angle,
last_collision_i_speed, last_collision_f_angle,
last_collision_f_speed) = collision_data
best_approx = 0
strictness_coef = 1.03
for memory_tuple in memory:
(x_miss, y_miss, x_collision, y_collision, _, _, f_angle, _) = memory_tuple.getData()
(divergence, x_divergence, y_divergence, f_angular_divergence) = calculateDivergence(memory_tuple, collision_data)
divergence = x_divergence + y_divergence + f_angular_divergence
approximation = (divergence, x_miss, y_miss)
printData("\n\nPAD: %s" % padindex)
printData("\nLAST COLLISION (X) = %s, CONSIDERED CASE (X) = %s" % (last_collision_x, x_collision))
printData("pos_x DIVERGENCE: %s" % x_divergence)
printData("\nLAST COLLISION (Y) = %s, CONSIDERED CASE (Y) = %s" % (last_collision_y, y_collision))
printData("pos_y DIVERGENCE: %s" % y_divergence)
printData("\nLAST COLLISION (fAngle) = %s, CONSIDERED CASE (fAngle) = %s" % (last_collision_f_angle, f_angle))
printData("FINAL ANGLE DIVERGENCE: %s" % f_angular_divergence)
printData("\nTOTAL DIVERGENCE: %s\n\n" % divergence)
if not best_approx:
best_approx = approximation
else:
(least_divergence, _, _) = best_approx
if divergence < least_divergence:
best_approx = approximation
(_, pos_x, pos_y) = best_approx
approximation = (pos_x, pos_y)
return approximation
.
计算并为存储在平板内存中的特定过去事件打分:
cdef calculateDivergence(memory_tuple, collision_data):
cdef double pos_x_dif
cdef double pos_y_dif
cdef double i_angle_dif
cdef double i_speed_dif
cdef double f_angle_dif
cdef double f_speed_dif
cdef double max_x_difference
cdef double max_y_difference
cdef double max_angular_difference
cdef double x_divergence
cdef double y_divergence
cdef double f_angular_divergence
cdef double total_divergence
(last_collision_x, last_collision_y, last_collision_i_angle,
last_collision_i_speed, last_collision_f_angle,
last_collision_f_speed) = collision_data
(x_miss, y_miss, x_collision, y_collision,
i_angle, i_speed, f_angle, f_speed ) = memory_tuple.getData()
pos_x_dif = abs(x_collision - last_collision_x)
pos_y_dif = abs(y_collision - last_collision_y)
i_angle_dif = getAngleDifference(i_angle, last_collision_i_angle)
i_speed_dif = abs(i_speed - last_collision_i_speed)
f_angle_dif = getAngleDifference(f_angle, last_collision_f_angle)
f_speed_dif = abs(f_speed - last_collision_f_speed)
max_x_difference = window_width
max_y_difference = window_height
max_angular_difference = 180
x_divergence = 100 * pos_x_dif / max_x_difference
y_divergence = 100 * pos_y_dif / max_y_difference
f_angular_divergence = 100 * f_angle_dif / max_angular_difference
#Apply weights.
x_divergence *= WeightData.current_weight
y_divergence *= WeightData.current_weight
f_angular_divergence *= (1 - WeightData.current_weight)
total_divergence = x_divergence + y_divergence + f_angular_divergence
divergence_data = (total_divergence, x_divergence, y_divergence, f_angular_divergence)
return divergence_data
编辑:Here's 分析代码的结果。 DrawSettingsMenu() 是最糟糕的方法之一,但可以忽略(默认情况下不显示设置菜单)。任何“初始化...”功能也可以忽略。
【问题讨论】:
我的第一个建议是测试你的代码慢的地方,不要猜测。所以你知道 X 函数在“总”中需要 Y 时间。 或者试试pypy
,它适用于纯Python代码。它不适用于所有 Python,但如果它适用于您的应用程序,那么您就是黄金。
这似乎是 CodeReview 提出的更好的问题
@EKS,代码现在已经分析过了,我只需要花时间分析它。
@MatthieuM.,我查看了 PyPy,但它现在似乎只支持 Python 2.7。不过听起来还是很有趣。
【参考方案1】:
您应该首先分析您的代码并查看需要优化的内容。 然后你应该尽可能地优化算法。 如果您发现 Python 中的某个函数太慢,您可以尝试使用 Cython 对其进行静态类型化,但使用 C 编写并从 Cython 调用它会获得更好的性能。但请确保您的代码在优化之前表现正确,否则您会浪费时间。
【讨论】:
【参考方案2】:如果您只是想让它更快,您可以尝试另一种 Python 实现,例如 PyPy 或 Unladen Swallow。如果您使用的是旧版本的 Python,您可能还想看看 Psyco。
【讨论】:
谢谢。不过,它们中的任何一个都支持 Python 3.2 吗? 还没有,但 PyPy 团队已经计划提供对它的支持。 如果他们能在接下来的几天左右完成它,那就太棒了,但我不认为我会那么幸运。 :p以上是关于使用 Cython 最大限度地提高性能的主要内容,如果未能解决你的问题,请参考以下文章
php 我创建的缩小php脚本,以最大限度地提高Googles页面速度得分