簡體   English   中英

在@njit numba 中設置 parallel=True 時實際發生了什么?

[英]What actually happens when setting parallel=True in @njit numba?

有人可以大致解釋一下當運行一個包含嵌套 for 循環的@njit -ted python 函數(每個循環的每次迭代都獨立於其他循環)並設置parallel=True並放置prange而不是range時會發生什么?

@njit(parallel=True)
def f():
    C = np.empty((80, 20, 18), dtype=np.complex128)
    for i in prange(80):
        for j in prange(20):
            for k in range(18):
            C[i, j, k] = do_smth(i, j, k) # where do_smth(i, j, k) is @njit-ted and will further call other functions

同樣,當只對最外層循環使用prange時會發生什么? (即讓for j in range(20): ...

我了解線程是什么,我將NUMBA_NUM_THREADS (環境變量)作為處理器的核心數。

我使用 timeit 模塊進行了一些分析,似乎parallel=True關鍵字僅在具有 20 個內核的機器上調用 .py 腳本時才減慢f()函數的執行速度(相當大(甚至慢了 4 倍) ))。

上面的f()進一步調用了更多函數(第一個是do_smth() ),它們的結構也類似於 f() 的結構(嵌套的 for 循環,在每次迭代中,調用其他 @njit-ted 函數)結構。 我如上所述檢查了它們。 我的方法好嗎? 即分析他們timeit並更改他們的 @njit 裝飾器中的關鍵字參數(我玩過parallelfastmathnogil )並創建一個表,我在其中記錄執行時間。 我的目標是從我獲得的結果中找到最佳執行時間。

有人可以大致解釋一下當運行一個包含嵌套 for 循環並設置 parallel=True 並放置 prange 而不是 range 的 @njit-ted python 函數時會發生什么?

在文檔中進行了解釋,但基本上,當設置了parallel=True時, prange將循環迭代拆分為塊,以便它們在多個線程中執行。 確切的調度取決於底層並行運行時(例如 TBB、OpenMP 等)。 循環由 Numba 分析,以便了解是否需要減少(並非所有模式都允許)。 如果需要,它還可以融合並行循環(盡管它在我的帶有 Numba 0.55.2 的機器上不起作用,即使在微不足道的縮減循環上:只有外部循環是並行化的)。 請注意,創建線程需要時間,並且內核數量越大,速度越慢。 這就是為什么多線程計算應該持續相對較長時間以便多線程有用的原因。

同樣,當只對最外層循環使用 prange 時會發生什么? (即讓 j 在 range(20): ... )

理論上,通常最好指定更多的並行度。 在實踐中,它並不總是有用,有時甚至是有害的,因為運行時可能會使用低效的方法(循環融合會導致慢模數與某些 OpenMP 后端一起使用)。

如果僅在基於i的外部循環上使用它,則僅並行化此循環(默認情況下使用所有內核,因此如果后端選擇了靜態調度,則每個循環進行 4 次迭代)。

我使用 timeit 模塊進行了一些分析,似乎 parallel=True 關鍵字僅在具有 20 個內核的機器上調用 .py 腳本時才減慢 f() 函數的執行速度(相當大(甚至慢 4 倍) ))。

並行編程並不容易 至少,遠遠超出大多數人的想象。 這就是為什么研究人員團隊為此工作了數十年,並且它仍然是一個活躍的研究領域。

有許多影響可以對此負責,包括:

  • 分配器爭用(非常頻繁)
  • 代碼中未定義的行為(頻繁):通常是競爭條件( 示例
  • 虛假分享(相當頻繁)
  • NUMA 效果(例如,訪問遠程頁面)
  • 其他資源飽和(例如內存),盡管它通常使代碼幾乎無法擴展並且不會導致減速(除非存在爭用)
  • Numba 中的一個錯誤(非常罕見)

另請注意,第一次調用會導致函數被編譯,因此速度較慢(並行代碼的編譯速度甚至更慢)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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