[英]Speed up NumPy loop
我正在Python中運行模型,並且試圖加快執行時間。 通過對代碼進行性能分析,我發現下面的cell_in_shadow
函數花費了大量的總處理時間。 我想知道是否有任何方法可以加快速度?
該函數的目的是提供一個布爾響應,說明NumPy數組中的指定單元是否被另一個單元遮蔽(僅在x方向上)。 它通過沿行向后退來檢查每個單元格相對於使給定單元格處於陰影中必須達到的高度來做到這一點。 shadow_map
中的值是由此處未顯示的另一個函數計算的-對於本示例,請使shadow_map
為具有類似於以下值的數組:
[0] = 0 (not used)
[1] = 3
[2] = 7
[3] = 18
add_x
函數用於確保數組索引循環(使用時鍾面算術),因為網格具有周期性邊界(任何偏離一側的東西將重新出現在另一側)。
def cell_in_shadow(x, y):
"""Returns True if the specified cell is in shadow, False if not."""
# Get the global variables we need
global grid
global shadow_map
global x_len
# Record the original length and move to the left
orig_x = x
x = add_x(x, -1)
while x != orig_x:
# Gets the height that's needed from the shadow_map (the array index is the distance using clock-face arithmetic)
height_needed = shadow_map[( (x - orig_x) % x_len)]
if grid[y, x] - grid[y, orig_x] >= height_needed:
return True
# Go to the cell to the left
x = add_x(x, -1)
def add_x(a, b):
"""Adds the two numbers using clockface arithmetic with the x_len"""
global x_len
return (a + b) % x_len
我確實同意Sancho的觀點,認為Cython可能是要走的路,但是這里有一些小提速:
A.在開始while循環之前grid[y, orig_x]
在某個變量中,並改用該變量。 這將節省大量對網格數組的查找調用。
B.由於您基本上只是從shadow_map中的x_len-1開始,一直工作到1,因此可以避免使用過多的模數。 基本上,更改:
while x != orig_x:
height_needed = shadow_map[( (x - orig_x) % x_len)]
至
for i in xrange(x_len-1,0,-1):
height_needed = shadow_map[i]
或只刪除height_needed變量,以及:
if grid[y, x] - grid[y, orig_x] >= shadow_map[i]:
這些都是很小的變化,但可能會有所幫助。
另外,如果您打算沿Cython路線行駛,我會考慮讓您的功能對整個網格執行此過程,或者至少一次執行一次。 這將節省大量的函數調用開銷。 但是,根據您使用結果的方式,您可能無法真正做到這一點。
最后,您是否嘗試過使用Psyco ? 它比Cython所需的工作更少,盡管它可能不會給您帶來那么大的速度提升。 我當然會先嘗試。
如果您不限於嚴格的Python,建議您使用Cython。 它可以允許對索引進行靜態輸入,並可以c速度高效,直接地訪問numpy數組的基礎數據緩沖區。
在http://wiki.cython.org/tutorials/numpy上查看簡短的教程/示例。
在該示例中,該操作與您正在執行的操作非常相似(增加索引,訪問numpy數組的各個元素),向索引變量中添加類型信息將與原始時間相比減少了一半的時間。 通過為numpy數組提供類型信息來為其添加有效的索引,可將時間縮短至原始數組的1%。
大多數Python代碼已經是有效的Cython,因此您可以使用已有的內容,並在需要的地方添加注釋和鍵入信息,以提高速度。
我懷疑您會從添加索引x
, y
, orig_x
和numpy數組的類型信息中獲得最大orig_x
。
以下指南比較了幾種優化python中數字代碼的方法:
它有點過時了,但仍然很有幫助。 請注意,它指的是派熱克斯(pyrex),此后被派生到創建Cython項目中,如Sancho所述。
就我個人而言,我更喜歡f2py,因為我認為fortran 90具有numpy的許多出色功能(例如,通過一個操作添加兩個數組),但是具有已編譯代碼的全速。 另一方面,如果您不了解fortran,那么這可能不是要走的路。
我簡短地嘗試了cython,發現的麻煩是默認情況下cython生成的代碼可以處理任意python類型,但速度仍然很慢。 然后,您必須花費時間添加所有必要的cython聲明,以使其更加具體和快速,而如果使用C或fortran,則往往會直接獲得快速的代碼。 同樣,這是由於我已經熟悉這些語言而產生的偏見,而如果Python是您所知道的唯一語言,則Cython可能更合適。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.