我正在尝试对从RGB值到16色调色板的颜色量化进行欧氏距离的小变化(我完全清楚这不是欧几里德公式)。我没有代码问题,但python中的性能比Java慢25倍。
python中的main方法如下所示:
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做错了什么,或者它本质上只是超级慢? 这是一个需要运行数百万次的过程,不,这不是图像处理(虽然看起来像)。
为Python和Java提供了全功能的最小代码here。
答案 0 :(得分:2)
使用NumPy,同时计算所有百万点:
{{1}}
时间:我系统上的0.9秒(你的Python代码在9s内执行)。另外,我是NumPy的新手,所以代码可能会进一步优化。
答案 1 :(得分:1)
由于您只想找到最近邻居进行颜色量化,因此您实际上并不需要按照您的方式计算所有距离。特别是,在这种情况下使用KDTree会更有效率。
否则,正如其他人已经注意到你得到的结果很慢,因为这些操作通常不会在纯Python中执行。默认方法是使用Numpy,在这种情况下,也可以使用Scipy中的专用函数加速(在这种情况下请参阅scipy.spatial.distance或更好scipy.spatial.cKDTree
)。最后,如果仍然不够好,你可以使用Cython,Pypy等。
答案 2 :(得分:0)
平原CPython本质上很慢 - 它来自解释器的设计。简言之,CPython是一个C ++程序,它不断从文件中读取指令,解析它们并采取相应的行动。
因此,对于每条指令,您都有从代码到C ++表示的完整“上下文切换”,包括所有名称查找,包装器转换,然后实际计算,然后返回到你的代码了。特别是循环是昂贵的,因为它意味着你一次又一次地做同样的事情。由于CPython是按行进行的,因此无法进行任何优化,例如预取数据,矢量化等。
优点是你可以通过非常简单的实现进行强大的内省和自我修改。不利的一面是,口译员必须在每一步都完成任务。
相比之下,Java和PyPy都是及时编译的。当他们经历一个循环时,他们会意识到他们已经做了同样的事情(指示明智)并为此做好准备。这就是为什么PyPy有时可能比CPython慢:它需要一个预热阶段,它可以实际上优化重复操作。如果操作只重复一点或从不重复,则没有任何优势。
免责声明:这是CPython解释器的简化视图。例如,存在一些“短路”指令,例如列表推导,其比常规循环更有效地处理。因为这些仍然可以调用任意代码,但它们的性能也受到限制。