两个跟并行计算加速相关的新开源项目-HVM & Bend

文摘   科技   2024-05-19 22:05   江苏  

最近在Github每日热榜上榜的有两个跟并行计算加速相关的开源项目,都是来自Higher Order Company这家公司。

在Github的公司主页上,写着如下介绍:

我们是HOC,一家科技初创公司,目标是构建不可避免的大规模并行计算机未来。我们相信:交互网络(Interaction Net)是一个强大的计算模型,它将催生出大规模并行的运行时和处理器。为了铺平前进的道路,我们开发了如下两个产品。

仓库:HigherOrderCO/HVM

点评: 高阶虚拟机(HVM)是Higher Order Compoany公司出品的,一个 Rust 中的大规模并行优化函数运行时。Higher Order Company官网首页自称其连接着“计算的并行未来”(WELCOME TO  THE PARALLEL  FUTURE OF COMPUTATION)。这个HVM通过将用高级语言(如 Python 和 Haskell)编写的程序编译为 HVM,人们就可以直接在大规模并行硬件(例如 GPU)上运行这些程序,并获得近乎理想的加速。

1997年,Yves Lafont设计了一种并发计算模型——交互组合器(Interaction Combinators),它在一些基本方面(如并行计算)超越了图灵机和λ-演算。HVM是基于该模型构建出来的一个高级语言编译器和评估器,它具有惰性、非垃圾回收和大规模并行等特性,可自动实现近乎理想的并行加速,最多可支持 1000 多个线程。在某些情况下,对于高阶计算,HVM的性能可能比包括GHC在内的其他方案都要快得多,甚至是指数级的快。

HVM目前是原型,即将推出包含大量优化和正确性工作的生产就绪版本。这种运行方式不仅内存高效(无需垃圾回收),还具有自动并行性β-最优性。这意味着,你只需编写一个简单的函数程序,HVM就能将其自动转换为大规模并行、β-最优的可执行程序。

HVM通过交互网模型实现,该模型是并发的计算模型,它允许数据在不同地方同时只出现一次,从而减少同步需求。HVM的内存占用与Rust相当,因为它即时收集任何无法到达的数据,没有累积的thunk,不需要全局垃圾回收。然而,HVM目前不实现如引用、循环和局部可变性等内存高效特性,因此其程序的内存占用可能比C和Rust程序大。

仓库:HigherOrderCO/Bend

点评: Bend(弯曲)是一种大规模并行高级编程语言,也是由 HigherOrder 公司出品,由前面介绍的 HVM2 运行时提供支持。

与 CUDA 和 Metal 等低级替代方案不同,Bend 和 Python 以及 Haskell 等具有高度表达力的编程语言有着相同的感觉和功能,包括快速对象分配、完全闭包支持的高阶函数、无限制的递归,甚至更多。同时它可以运行在 GPU 等大规模并行硬件上,具有基于核心数量的近线性加速,以及零显式并行注释:没有线程生成、没有锁、没有互斥、没有原子操作等并行计算中的这些烦人东西,任何可以并行完成的工作都将并行完成。

用官方的说法:使用 Bend,你可以轻松地为多核 CPU/GPU 编写并行代码,而无需成为具有 10 年经验的 C/CUDA 老专家。感觉就像在用Python编程一样!也无需处理并发编程的复杂性:锁、互斥体、原子……

要在 Bend 中编写并行程序,你要做的就是……什么都不做。除了不要把程序写成本质上必须顺序执行的除外!比如写成如下这样的表达式:

((1 + 2) + (3 + 4))

这段表达式天然就无法并行运行,因为 +4 依赖于 +3 ,而 +3 又依赖于 (1+2) 。但下面这个表达式:

((1 + 2) + (3 + 4))

却可以并行运行,因为 (1+2) 和 (3+4) 是独立的;根据Bend的基本承诺,它将做到:

Everything that can run in parallel, will run in parallel.

一切能并行运行的东西都会并行运行。

更完整的示例,可以看如下双调排序相关的代码:

(并行双调排序)

# 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 imagedef 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 loopsdef 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_shaderdef main: return render(16, demo_shader)

它确实会起作用。即使涉及的算法在 Bend 上也能很好地并行。长距离通信通过全局 beta 缩减(根据交互演算)执行,并通过 HVM2 的原子链接器正确有效地同步。

要直接开始操作,请查看 Bend 的 GUIDE.md。

有关详细功能列表,请查看 FEATURES.md。

要了解 Bend 背后的技术,请查看 HVM2 的论文。

官方最后指出:

需要强调的是,虽然 Bend 实现了它的初衷(即通过内核扩展性能,最多可支持 10000+  个并发线程),但它的单核性能仍然非常低于标准。这是该系统的第一个版本,我们还没有在合适的编译器上投入太多精力。您可以预期每个版本的原始性能都会大幅提高,因为我们致力于正确的代码生成(包括一系列缺失的优化)。同时,您现在可以使用解释器,从 Python 高级语言的角度一睹大规模并行编程的样子!

天马行空的大杂烩
“我不能选择那最好的,是那最好的选择我。”-泰戈尔 💖欢迎来到这里。我天马行空地写,您随心所欲地看。欢迎就我们感兴趣的内容交流学习😀🤝
 最新文章