[英]Python2 poor performance in simple math operations
我正在尝试对从 RGB 值到 16 色调色板的颜色量化进行欧几里德距离的小变化(我完全意识到这不是欧几里德公式)。 我的代码没有问题,但 python 的性能比 Java 慢 25 倍以上。
python中的主要方法如下所示:
def getBaseColor(rValue=128, gValue=128, bValue=128):
allDistances=[450]*16
for x in range(0,16):
valoresColor = coloresWeb[x]
allDistances[x]= (abs(valoresColor[0]-rValue) + abs(valoresColor[1]-gValue) + abs(valoresColor[2]-bValue))
return allDistances.index(min(allDistances))
我做了小型基准测试(1M 次操作),Java 比 Python(2.7.9)快 25 倍。 使用 pypy 有很大帮助,但离 Java 还很远。
Python 2:~5.2s
Java:~0.2s
pypy:~0.6s
我的问题是:我是不是用 python 做错了什么,或者它本质上是超级慢的?。 这是一个需要运行亿次的过程,不,这不是图像处理(虽然看起来像)。
使用NumPy,可以同时计算所有百万分:
import time
import numpy as np
webColours = np.array([
[0,0,0],
[0,0,128],
[0,128,0],
[0,128,128],
[128,0,0],
[128,0,128],
[128,128,0],
[192,192,192],
[128,128,128],
[0,0,255],
[0,255,0],
[0,255,255],
[255,0,0],
[255,0,255],
[255,255,0],
[255,255,255]
])
def getBaseColours(colours):
# colours is 1000000x3
# set up a distances array (16x1000000)
distances = np.zeros((16, np.size(colours, 0)))
for colour in xrange(16):
# calculate distance of each input colour to this webColour
distances[colour] = np.sum(abs(colours - webColours[colour]), 1)
# which of 16 distances is the least for each of 1000000 colours
return np.argmin(distances, 0)
startTime = time.time()
colour = np.array([134,234,43])
colours = np.tile(colour, (1000000, 1))
getBaseColours(colours)
print "Time: " + str(time.time()-startTime)
时间:在我的系统上为0.9秒(您的Python代码在9秒内执行)。 另外,我是NumPy的新手,因此可能可以进一步优化代码。
由于您只想找到一个最近的邻居进行色彩量化,因此实际上您不需要按照自己的方式计算所有距离。 特别是在这种情况下使用KDTree会更加有效。
否则,正如其他人指出的那样,使用Python的结果会很慢,因为此类操作通常不会在纯Python中执行。 默认方法是使用Numpy,在这种情况下,也可以使用Scipy的专用功能(请参阅scipy.spatial.distance或在这种情况下为scipy.spatial.cKDTree
更好)来加快速度。 最后,如果仍然不够好,可以使用Cython,Pypy等。
普通的CPython本质上很慢-它来自解释器的设计。 简而言之,CPython是一个C ++程序,它不断从文件中读取指令,对其进行解析并采取相应的行动。
因此,对于每条指令,您都有完整的“上下文切换”,从代码一直到其在C ++中的表示形式,包括所有名称查找,包装程序的转换, 然后是实际的计算,然后再次返回到您的代码。 循环尤其昂贵,因为循环意味着您一次又一次地执行相同的操作。 由于CPython按行运行,因此它无法进行任何优化,例如预取数据,向量化等。
好处是,您可以通过非常简单的实现进行强大的自省和自我修改。 不利的一面是,口译员必须在每一步都走一路。
相反,Java和PyPy都是即时编译的。 当他们经历一个循环时,他们将意识到他们已经做过同样的事情(在指令方面)并为此做好了准备。 这就是为什么PyPy有时可能比CPython慢的原因:它需要一个预热阶段,在该阶段中它实际上可以优化重复的操作。 如果仅重复操作一次或从不重复操作,则没有优势。
免责声明:这是CPython解释器的非常简化的视图。 例如,有些“短路”指令(例如列表理解)比常规循环更有效地处理。 由于它们仍然可以调用任意代码,因此它们的性能也受到限制。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.