[英]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.