最多可支援 10000+ 個併發執行緒。
經過近 10 年的不懈努力,對電腦科學核心的深入研究,人們終於實現了一個夢想:在 GPU 上執行高階語言。
上週末,一種名為 Bend 的程式語言在開源社群引發了熱烈的討論,GitHub 的 Star 量已經超過了 8500。
GitHub:https://github.com/HigherOrderCO/Bend
作為一種大規模並行的高階程式語言,它仍處於研究階段,但提出的思路已經讓人們感到非常驚訝。使用 Bend,你可以為多核 CPU/GPU 編寫並行程式碼,而無需成為具有 10 年經驗的 C/CUDA 專家,感覺就像 Python 一樣!
是的,Bend 採用了 Python 語法。
與 CUDA、Metal 等低階替代方案不同,Bend 具有 Python、Haskell 等表達性語言的功能,包括快速物件分配、完全閉包支援的高階函式、無限制的遞迴,甚至 continuation。Bend 執行在大規模並行硬體上,具有基於核心數量的近線性加速。Bend 由 HVM2 執行時提供支援。
該專案的主要貢獻者 Victor Taelin 來自巴西,他在 X 平臺上分享了 Bend 的主要特性和開發思路。
首先,Bend 不適用於現代機器學習演算法,因為這些演算法是高度正則化的(矩陣乘法),具有預先分配的記憶體,並且通常已經有編寫好的 CUDA 核心。
Bend 的巨大優勢體現在實際應用中,這是因為「真正的應用程式」通常沒有預算來製作專用的 GPU 核心。試問,誰在 CUDA 中製作了網站?而且,即使有人這樣做了,也是不可行的,因為:
1. 真正的應用程式需要從許多不同的庫匯入函式,無法為它們編寫 CUDA 核心;
2. 真實的應用程式具有動態函式和閉包;
3. 真實的應用程式會動態且不可預測地分配大量記憶體。
Bend 完成了一些新的嘗試,並且在某些情況下可以相當快,但現在想寫大語言模型肯定是不行的。
作者對比了一下舊方法和新的方法,使用相同的演算法樹中的雙調排序,涉及 JSON 分配和操作。Node.js 的速度是 3.5 秒(Apple M3 Max),Bend 的速度是 0.5 秒(NVIDIA RTX 4090)。
是的,目前 Bend 需要整塊 GPU 才能在一個核心上擊敗 Node.js。但另一方面,這還是一個初生的新方法與大公司(Google)最佳化了 16 年的 JIT 編譯器在進行比較。未來還有很多可能性。
如何使用
在 GitHub 上,作者簡要介紹了 Bend 的使用流程。
首先,安裝 Rust。如果你想使用 C 執行時,請安裝 C 編譯器(例如 GCC 或 Clang);如果要使用 CUDA 執行時,請安裝 CUDA 工具包(CUDA 和 nvcc)版本 12.x。Bend 目前僅支援 Nvidia GPU。
然後,安裝 HVM2 和 Bend:
cargo +nightly install hvm
cargo +nightly install bend-lang
最後,編寫一些 Bend 檔案,並使用以下命令之一執行它:
bend run <file.bend> # uses the Rust interpreter (sequential)
bend run-c <file.bend> # uses the C interpreter (parallel)
bend run-cu <file.bend> # uses the CUDA interpreter (massively parallel)
你還可以使用 gen-c 和 gen-cu 將 Bend 編譯為獨立的 C/CUDA 檔案,以獲得最佳效能。但 gen-c、gen-cu 仍處於起步階段,遠沒有像 GCC 和 GHC 這樣的 SOTA 編譯器那麼成熟。
Bend 中的並行程式設計
這裡舉例說明可以在 Bend 中並行執行的程式。例如,表示式:
(((1 + 2) + 3) + 4)
不能並行執行,因為 + 4 取決於 + 3,而 + 3 又取決於 (1+2)。而表示式:
((1 + 2) + (3 + 4))
可以並行執行,因為 (1+2) 和 (3+4) 是獨立的。Bend 並行執行的條件就是符合並行邏輯。
再來看一個更完整的程式碼示例:
# Sorting Network = just rotate trees!
def sort (d, s, tree):
switch d:
case 0:
return tree
case _:
(x,y) = tree
lft = sort (d-1, 0, x)
rgt = sort (d-1, 1, y)
return rots (d, s, lft, rgt)
# Rotates sub-trees (Blue/Green Box)
def rots (d, s, tree):
switch d:
case 0:
return tree
case _:
(x,y) = tree
return down (d, s, warp (d-1, s, x, y))
(...)
該檔案實現了具有不可變樹旋轉的雙調排序器。它不是很多人期望的在 GPU 上快速執行的演算法。然而,由於它使用本質上並行的分治方法,因此 Bend 會以多執行緒方式執行它。一些速度基準:
CPU,Apple M3 Max,1 個執行緒:12.15 秒
CPU,Apple M3 Max,16 執行緒:0.96 秒
GPU,NVIDIA RTX 4090,16k 執行緒:0.21 秒
不執行任何操作即可實現 57 倍的加速。沒有執行緒產生,沒有鎖、互斥鎖的顯式管理。我們只是要求 Bend 在 RTX 上執行我們的程式,就這麼簡單。
Bend 不限於特定範例,例如張量或矩陣。任何的併發系統,從著色器到類 Erlang 的 actor 模型都可以在 Bend 上進行模擬。例如,要實時渲染影像,我們可以簡單地在每個幀上分配一個不可變的樹:
# given a shader, returns a square image
def render (depth, shader):
bend d = 0, i = 0:
when d < depth:
color = (fork (d+1, i*2+0), fork (d+1, i*2+1))
else:
width = depth / 2
color = shader (i % width, i /width)
return color
# given a position, returns a color
# for this demo, it just busy loops
def demo_shader (x, y):
bend i = 0:
when i < 5000:
color = fork (i + 1)
else:
color = 0x000001
return color
# renders a 256x256 image using demo_shader
def main:
return render (16, demo_shader)
它確實會起作用,即使涉及的演算法在 Bend 上也能很好地並行。長距離通訊透過全域性 beta 縮減(根據互動演算)執行,並透過 HVM2 的原子連結器正確有效地同步。
最後,作者表示 Bend 現在僅僅是第一個版本,還沒有在合適的編譯器上投入太多精力。大家可以預期未來每個版本的原始效能都會大幅提高。而現在,我們已經可以使用直譯器,從 Python 高階語言的角度一睹大規模並行程式設計的樣子了。
參考內容:
https://news.ycombinator.com/item?id=40390287
https://x.com/VictorTaelin?ref_src=twsrc%5Egoogle%7Ctwcamp%5Eserp%7Ctwgr%5Eauthor
https://x.com/DrJimFan/status/1791514371086250291