執行緒和執行

並行的關鍵是使用多個執行緒來解決問題(duh。)但是線上程的組織方式上,經典的多執行緒程式設計存在一些差異。

首先讓我們談談你的典型 GPU,為了簡單起見,我將重點關注

GPU 具有許多處理核心,這使其成為並行執行多個執行緒的理想選擇。這些核心在流處理器(SM,NVidia 術語)中組織,其中 GPU 具有給定數量。

在 SM 內部執行的所有執行緒都稱為執行緒塊。SM 上可以有比執行緒更多的執行緒。核心數量定義了所謂的扭曲大小(NVidia 術語)。執行緒塊內的執行緒被稱為 warps

一個跟進的快速示例:典型的 NVidia SM 有 32 個處理核心,因此它的 warp 大小為 32.如果我的執行緒塊現在有 128 個執行緒要執行,它們將被束縛為 4 個經線(4 個經線* 32 個經線尺寸= 128 個)執行緒)。

稍後選擇執行緒數時,warp 大小非常重要。

單個 warp 中的所有執行緒共享一個指令計數器。這意味著這 32 個執行緒真正同步,因為每個執行緒同時執行每個命令。這是一個效能缺陷:這也適用於核心中的分支語句!

示例:我有一個核心,它有一個 if 語句和兩個分支。在 warp 中我的 16 個執行緒將執行分支一,另一個 16 分支兩個。直到 if 語句,warp 中的所有執行緒都是同步的。現在有一半人選擇了不同的分支。發生的事情是,另一半將處於休眠狀態,直到錯誤的語句在前 16 個執行緒上執行完畢。然後這些執行緒將處於休眠狀態,直到其他 16 個執行緒完成其分支。

正如你所看到的,糟糕的分支習慣會嚴重降低並行程式碼的速度,因為這兩個語句都會在最壞的情況下執行。如果 warp 中的所有執行緒決定它們只需要其中一個語句,則完全跳過另一個並且不會發生延遲。

同步執行緒也不是一件簡單的事情。你只能使用單個 SM 同步執行緒。SM 之外的所有內容在核心中都是不可同步的。你必須編寫單獨的核心並一個接一個地啟動它們。