为什么是 l(k 和 q 的新运行时)
摘要
K 和 Q 编程语言的新运行时,利用 SIMD、并行、融合和压缩技术重新构想执行方式,以更好地发挥现代硬件的性能。
<p><a href="https://lobste.rs/s/wkm8tk/why_l_new_runtime_for_k_q">评论</a></p>
查看缓存全文
缓存时间: 2026/07/21 08:39
# Why l. | l
来源:https://lv1.sh/blog/why-l/
我从 2001 年开始接触 K 和 Q,至今已近二十五年。首先说一个显而易见的事实:Arthur Whitney 是个天才。
K 和 Q 至今仍是非凡的语言。它们的设计精巧、紧凑、优美。但尽管经过了多年的优化、扩展和修正,核心的实现模型仍然扎根于 Arthur 在 20 世纪 90 年代的原始洞见。
我并非想要改变这门语言。我还没有狂妄到觉得自己应该发明一种新语言。我想做的是,针对我们今天实际使用的机器,重新构想其实现。
2026 年的计算机已经不是 1997 年的计算机了。CPU 更宽。内存相对更慢。每台机器都有多个核心。许多机器还配有 GPU、NPU、AMX 单元、NEON、AVX、VNNI 以及其他专用执行引擎。硬件已经发生了巨大的变化,而编程模型却没有跟上。
l 是我试图在保留语言(K、Q、qSQL、IPC,以及整个现有代码世界)的同时,重构底层执行引擎的一次尝试。该实现围绕四个核心理念构建:**SIMD、并行性、融合和压缩**。
## SIMD 作为一等原始操作
我希望每个运算符都能自动利用硬件优势。在考虑集群、GPU 或分布式系统之前,一个更简单的问题是:每个原始操作在单核上能有多快?
这意味着让每一个时钟周期都物尽其用。这意味着将 SIMD 视为原始操作执行的默认路径,而非可选的优化手段。如果硬件每条指令能处理多个值,语言就应该自动利用这一点,无需重写代码,无需向量内建函数,也无需用户思考。原始操作就应该是快速的。
## 默认并行
并行性对于数组语言来说一直是自然而然的事情。APL、K 和 Q 都将工作表达为对数组进行的大规模、规则操作,而这正是现代 CPU 能够利用的结构。
但我希望从头开始思考这个问题。l 将并行执行视为原始运行时的一部分,而非将它作为外部工具拼接过来。小数组走快速单核 SIMD 路径。更大的数组自动在多个工作线程间拆分。用户从不需要决定何时并行化;运行时根据操作的大小、形状和成本来决定。
当数组变得更大时,同样的思路会扩展到加速器上。在一台现代 Apple 机器上,许多工作负载太小,不值得将数据移交给 GPU,但有些则不是。小值留在 CPU 流水线上。较大的值使用线程。最大的操作在划算时移交给 GPU、NPU 或其他后端。你不应该因为硬件变化就需要使用不同版本的语言。
## 透明融合
当我在金融服务中使用 K 和 Q 时,代码通常很优雅。当它变慢时,原因很少是原始操作本身,而是中间结果的分配。
你写了一些漂亮的代码:
``
q) sum sqrt x
``
概念上很简单:对每个值取平方根,然后求和。但传统的实现可能会为 `sqrt x` 分配一整个中间向量,紧接着在 `sum` 中把它消耗掉。这种分配就是浪费。
l 使融合变得透明。运行时会链式组合原始操作,并尽可能消除中间对象。在 `sum sqrt x` 中,求和循环直接消费取平方根后的值。在安全的情况下,它会原地修改临时变量。在可能的情况下,它会将整个表达式压缩成一个流水线。你仍然写普通的 K 或 Q 代码。实现让显而易见的事变得快速。
## 压缩作为运行时概念
第四个理念,也是最困难、或许也是最重要的,是压缩。它不应该是一个放在旁边的存储功能,它应该是运行时内部的一等概念。
一个运算符不应该关心它操作的对象是否被压缩。运行时应该知道如何直接操作压缩数据。为了让压缩、SIMD、线程化和融合能够正确组合,它们必须被一起设计。这是核心的实现挑战。
除了少数例外,大多数原始操作可以直接处理压缩数据。一个巨大的向量可以保持压缩状态,在内存中移动更少的字节,更好地适应缓存,并且仍然产生相同的结果。
> 内存带宽是敌人。现代 CPU 非常快。瓶颈很少是算术计算,而是数据移动:从 RAM 到缓存,从缓存到寄存器,从核心到核心,从 CPU 到加速器。
让软件变快的最简单方法是,在更短的距离内移动更少的数据。这就是为什么压缩对 l 如此重要。如果一个向量能用更少的字节表示,l 就会保持这种状态。如果数据能留在缓存中,它就留在缓存中。如果一个操作可以在不解压完整向量的情况下执行,它就这样做。运行时只移动计算正确答案所需的最少字节数。
## 护栏:完全兼容 K 和 Q
所有这些的护栏是兼容性。我希望 l 就是 K 和 Q,而不是“受 K 启发”,不是“类似 Q”。我希望现有的商用 k4 和 Q 代码无需修改即可运行。我不想抛弃二十多年的代码、谜题和我成长的社区。
这意味着要实现这门语言、qSQL、IPC 以及周围的执行模型,并且要拿真实的代码(不仅仅是示例)来问:它能否实际在更大的系统中运行?一旦你承诺做到这一点,问题就会变得困难得多,也更有意义得多。
l 的目的不是创造一门新语言然后让人们迁移。目的是保留语言,并替换底层的机器。**相同的语言。全新的引擎。**
K 和 Q 给了我们有史以来构建过的最强大的数组编程模型之一。l 要问的是,当实现从头开始为现代硬件设计时(默认采用 SIMD,默认并行,默认融合,默认压缩),这个模型会是什么样子。
这就是我构建 l 的原因。
相似文章
l: 用于 k 和 q 的新运行时
l 是一个用于 k4、q 和 qSQL 的新运行时,提供透明的 SIMD、压缩向量和自动并行性,同时保持与现有代码的完全兼容。它针对华尔街的高性能计算。
一个用于本地LLM的"能跑吗"计算器(考虑量化与KV缓存)
一个网络工具,通过考虑量化、KV缓存和VRAM开销,计算给定本地LLM能否在指定硬件上运行,并提供预估速度和内存使用。
QBE – 编译器后端
QBE 是一个紧凑的、爱好级别的编译器后端,仅用 10% 的代码即可实现工业级优化编译器 70% 的性能,支持 amd64、arm64 和 riscv64,并采用简单的基于 SSA 的中间语言。
llama.cpp PR 报告:仅切换一个 SYCL 内核,Intel Battlemage 上量化 KV 解码在 118K 上下文最高提速 169%
llama.cpp 的一个 PR 提议将 Intel Battlemage 上的量化 KV 解码从 VEC 切换到 TILE SYCL 内核,据报道在 118K 上下文下解码速度提升最高约 169%。该 PR 目前处于开放状态,存在一些注意事项,且独立验证有限。
@elliotarledge:对于那些好奇我为什么使用 Kimi Linear 巨型内核而不是 Qwen 3.6 的人,首先看看参数数量。一个是……
Elliot Arledge 解释了他为什么更喜欢使用 Kimi Linear 巨型内核而不是 Qwen 3.6 来提升内核性能,比较了参数数量、层同步、隐藏维度和架构特定的优化。讨论强调 Kimi Linear 架构更适合巨型内核实现,特别是在 RTX PRO 6000 Blackwell 上进行 batch-1 解码时。