HigherOrderCO/Bend

GitHub: HigherOrderCO/Bend

Bend 是一种无需显式并行标注即可自动在 GPU 等大规模并行硬件上运行的高级编程语言,解决了并行编程中手动管理线程和锁的复杂性问题。

Stars: 19723 | Forks: 494

Bend

一种高级、大规模并行的编程语言

## 目录 1. [简介](#introduction) 2. [重要提示](#important-notes) 3. [安装](#install) 4. [快速入门](#getting-started) 5. [加速示例](#speedup-examples) 6. [其他资源](#additional-resources) ## 简介 Bend 提供了类似 Python 和 Haskell 等富有表现力的语言的风格和特性。这包括快速的对象分配、对带有闭包的高阶函数的全面支持、无限制的递归,甚至包括 continuations。 Bend 像 CUDA 一样具备扩展性,它可以运行在 GPU 等大规模并行硬件上,根据核心数量实现近乎线性的加速,并且不需要显式的并行标注:没有线程创建、锁、mutexes 或 atomics。 Bend 由 [HVM2](https://github.com/higherorderco/hvm) 运行时提供支持。 ## 重要提示 * Bend 旨在实现核心性能的卓越扩展,支持超过 10000 个并发线程。 * 当前版本的单核性能可能较低。 * 随着我们改进代码生成和优化技术,您可以预期其性能将得到大幅提升。 * 我们仍在努力支持 Windows。请使用 [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install) 作为替代方案。 * [我们目前仅支持 NVIDIA GPU](https://github.com/HigherOrderCO/Bend/issues/341)。 ## 安装 ### 安装依赖 #### 在 Linux 上 ``` # 如果你还没有安装 Rust,请先安装。 curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # 对于 C 版本的 Bend,请使用 GCC。我们推荐使用 12.x 及以下的版本。 sudo apt install gcc ``` 对于 CUDA 运行时,请[安装 12.x 版本的 Linux CUDA 工具包](https://developer.nvidia.com/cuda-downloads?target_os=Linux)。 #### 在 Mac 上 ``` # 如果你还没有安装 Rust,请先安装。 curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # 对于 C 版本的 Bend,请使用 GCC。我们推荐使用 12.x 及以下的版本。 brew install gcc ``` ### 安装 Bend 1. 运行以下命令安装 HVM2: ``` # HVM2 是 HOC 的大规模并行 Interaction Combinator evaluator。 cargo install hvm # 这确保 HVM 已正确安装并且可以访问。 hvm --version ``` 2. 运行以下命令安装 Bend: ``` # 此命令将安装 Bend cargo install bend-lang # 这确保 Bend 已正确安装并且可以访问。 bend --version ``` ### 快速入门 #### 运行 Bend 程序 ``` bend run # uses the C interpreter by default (parallel) bend run-rs # uses the Rust interpreter (sequential) bend run-c # uses the C interpreter (parallel) bend run-cu # uses the CUDA interpreter (massively parallel) # 注意事项 # 你还可以使用 gen-c 和 gen-cu 将 Bend 编译为独立的 C/CUDA 文件,以获得最佳性能。 # 代码生成器仍处于早期阶段,不如 GCC 和 GHC 等编译器成熟。 # 你可以使用 -s 标志来获取更多信息 # Reductions # Time the code took to run # Interaction per second (In millions) ``` #### 测试 Bend 程序 下面的示例计算从 `start` 到 `target` 范围内所有数字的总和。它可以用两种不同的方法编写:一种是天生顺序执行的(因此无法并行化),另一种则很容易并行化。(为了便于演示,我们将在大多数示例中使用 `-s` 标志) #### 顺序版本: 首先,创建一个名为 `sequential_sum.bend` 的文件 ``` # 在你的终端中输入此命令 touch sequential_sum.bend ``` 然后使用您的文本编辑器打开文件 `sequential_sum.bend`,复制下面的代码并将其粘贴到文件中。 ``` # 定义带有两个参数的函数 Sum:start 和 target def Sum(start, target): if start == target: # If the value of start is the same as target, returns start. return start else: # If start is not equal to target, recursively call Sum with # start incremented by 1, and add the result to start. return start + Sum(start + 1, target) def main(): # This translates to (1 + (2 + (3 + (...... + (999999 + 1000000))))) # Note that this will overflow the maximum value of a number in Bend return Sum(1, 1_000_000) ``` ##### 运行文件 您可以使用 Rust 解释器(顺序执行)运行它 ``` bend run-rs sequential_sum.bend -s ``` 或者您可以使用 C 解释器(顺序执行)运行它 ``` bend run-c sequential_sum.bend -s ``` 如果您有 NVIDIA GPU,您也可以在 CUDA 上运行(顺序执行) ``` bend run-cu sequential_sum.bend -s ``` 在这个版本中,下一个要计算的值取决于前一次的总和,这意味着在当前计算完成之前它无法继续进行。现在,让我们看看那个容易并行化的版本。 #### 可并行化版本: 首先关闭旧文件,然后转到您的终端创建 `parallel_sum.bend` ``` # 在你的终端中输入此命令 touch parallel_sum.bend ``` 然后使用您的文本编辑器打开文件 `parallel_sum.bend`,复制下面的代码并将其粘贴到文件中。 ``` # 定义带有两个参数的函数 Sum:start 和 target def Sum(start, target): if start == target: # If the value of start is the same as target, returns start. return start else: # If start is not equal to target, calculate the midpoint (half), # then recursively call Sum on both halves. half = (start + target) / 2 left = Sum(start, half) # (Start -> Half) right = Sum(half + 1, target) return left + right # 一个可并行的从 1 到 1000000 的数字求和 def main(): # This translates to (((1 + 2) + (3 + 4)) + ... (999999 + 1000000)...) return Sum(1, 1_000_000) ``` 在这个示例中,(3 + 4) 的和并不依赖于 (1 + 2),这意味着它可以并行运行,因为这两次计算可以同时发生。 ##### 运行文件 您可以使用 Rust 解释器(顺序执行)运行它 ``` bend run-rs parallel_sum.bend -s ``` 或者您可以使用 C 解释器(并行执行)运行它 ``` bend run-c parallel_sum.bend -s ``` 如果您有 NVIDIA GPU,您也可以在 CUDA 上运行(大规模并行) ``` bend run-cu parallel_sum.bend -s ``` 在 Bend 中,只需更改运行命令即可实现并行化。如果您的代码**可以**并行运行,它**就一定**会并行运行。 ### 加速示例 下面的代码片段实现了一个带有*不可变树旋转*的 [双调排序器](https://en.wikipedia.org/wiki/Bitonic_sorter)。这不是那种您会期望在 GPU 上快速运行的算法。然而,由于它采用了本质上并行的分而治之方法,Bend 将在多个线程上执行它,不需要线程创建,也不需要显式的锁管理。 #### 双调排序器基准测试 - `bend run-rs`:CPU,Apple M3 Max:12.15 秒 - `bend run-c`:CPU,Apple M3 Max:0.96 秒 - `bend run-cu`:GPU,NVIDIA RTX 4090:0.21 秒
点击此处查看双调排序器代码 ``` # Sorting Network = 只需旋转树! 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)) # 旋转子树(蓝/绿框) 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)) # 交换远处的值(红框) def warp(d, s, a, b): switch d: case 0: return swap(s ^ (a > b), a, b) case _: (a.a, a.b) = a (b.a, b.b) = b (A.a, A.b) = warp(d-1, s, a.a, b.a) (B.a, B.b) = warp(d-1, s, a.b, b.b) return ((A.a,B.a),(A.b,B.b)) # 向下传播 def down(d,s,t): switch d: case 0: return t case _: (t.a, t.b) = t return (rots(d-1, s, t.a), rots(d-1, s, t.b)) # 交换一对值 def swap(s, a, b): switch s: case 0: return (a,b) case _: return (b,a) # 测试 # ------- # 生成一棵大树 def gen(d, x): switch d: case 0: return x case _: return (gen(d-1, x * 2 + 1), gen(d-1, x * 2)) # 对一棵大树求和 def sum(d, t): switch d: case 0: return t case _: (t.a, t.b) = t return sum(d-1, t.a) + sum(d-1, t.b) # 对一棵大树排序 def main: return sum(20, sort(20, 0, gen(20, 0))) ```
如果您对其他算法感兴趣,可以查看我们的 [examples 文件夹](https://github.com/HigherOrderCO/Bend/tree/main/examples) ### 其他资源 - 要了解 Bend 背后的技术,请查看 HVM2 [论文](https://paper.higherorderco.com/)。 - 我们正在编写官方文档,同时如需更深入的了解, 请查看 [GUIDE.md](https://github.com/HigherOrderCO/Bend/blob/main/GUIDE.md) - 请在 [FEATURES.md](https://github.com/HigherOrderCO/Bend/blob/main/FEATURES.md) 阅读关于我们的功能特性 - Bend 由 [HigherOrderCO](https://higherorderco.com/) 开发 - 加入我们的 [Discord](https://discord.higherorderco.com)!
标签:Rust, Vectored Exception Handling, 可视化界面, 并行计算, 编程语言, 网络流量审计, 通知系统, 高性能计算