簡體   English   中英

Python2在簡單的數學運算中表現不佳

[英]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 做錯了什么,或者它本質上是超級慢的?。 這是一個需要運行億次的過程,不,這不是圖像處理(雖然看起來像)。

這里為 Python 和 Java 提供功能齊全的最小代碼。

使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM