首页 时政热点 科技头条 智能AI 安全攻防 数码硬件 开发者生态 汽车 游戏 社会热点 开源推荐 医疗健康 归档 标签 关于

5μs JIT 编译代码

2026-08-23 1 阅读 约8分钟阅读 zX41ZdbW
分享:
字号:
从历史上看,快速 JIT 编译是一门黑术。要编写快速 JIT 编译器,您需要知道如何编写汇编。典型的例子是:目前还没有可用于生产的数据库拥有自己的 JIT 编译器。它们都使用 LLVM 或生成 C/C++ 代码。这两个选项的编译时间都很长,这限制了它们的适用性。现在,随着人工智能的使用,通过直接针对汇编来编写具有快速编译时间的 JIT 编译器比以往任何时候都更容易。这也是新数据库改进旧数据库的机会之一。在构建 pgrust 时,我最初认为实现 JIT 编译器真的很难。最后,我发现由于人工智能的帮助,它比我预期的要容易得多,这最终成为 prust 如此快的部分原因。 pgrust JIT 编译器在大约 5μs 内编译代码,这使我们能够 JIT 编译每个 SQL 查询,而不仅仅是它们的子集。在这篇文章中,我将引导您了解如何构建自己的快速 JIT 编译器。我们将构建一个简单的正则表达式引擎,以 JIT 编译为例。为什么 JIT 编译 JIT 编译是在运行时或“即时”生成编译代码的做法。如果做得正确,它可以带来巨大的性能提升,通常是 2-5 倍,有时甚至更多。 JIT 编译的主要用例是当您在运行时获得的信息会极大地改变程序的行为时。这对于编程语言解释器来说尤其常见;他们接收在运行时执行的代码。 JIT 编译器在编程语言以外的领域也很有用,例如解析数据。有时,直到运行时您才知道正在解析的数据的模式,而 JIT 可以帮助解决这个问题。首先,让我们实现一个玩具正则表达式引擎。为了简单起见,我们将仅支持两个功能:文字字符串和重复(即正则表达式 *)。我们还将跳过解析器并将正则表达式表示为已解析的 Rust 结构。这意味着我们将能够支持诸如以下的字符串:但不能支持交替或向后查找或类似的内容。在代码中这非常简单。我们将有 3 种类型的节点:文字字符串节点、重复节点和串联节点(两个节点的组合)。最终看起来像这样: enum Node { Literal(&'static str), Concatenation(Box, Box), Repetition(Box), } fn Literal(text: &'static str) -> Node { Node::Literal(text) } fn concatenation(left: Node, right: Node) -> Node { Node::Concatenation(Box::new(left), Box::new(right)) } fn repetition(body: Node) -> Node { Node::Repetition(Box::new(body)) } 为正则表达式引擎编写解释器也很简单: fn match_node(node: &Node, input: &[u8], pos: usize, next: &dyn Fn(usize) -> bool) -> bool { match node { Node::Literal(text) => { letliteral = text.as_bytes(); } input[pos..].starts_with(literal) && next(pos +literal.len()) } Node::Concatenation(left, right) => { match_node(left, input, pos, &|left_end| { match_node(right, input, left_end, next) }) } Node::Repetition(body) => { match_node(body, input, pos, &|body_end| { match_node(node,输入,body_end,下一个)})|| next(pos) } } } fn interp_match(regex: &Node, input: &str) -> bool { let bytes = input.as_bytes(); match_node(regex, bytes, 0, &|pos| pos == bytes.len()) } 现在这个正则表达式引擎非常简单。它的代码不到 20 行,但让我们看看它的性能如何。为了进行比较,我们将代码与专门为正则表达式实现的手写代码进行比较。对于我们的示例,我们将使用正则表达式 b(an)*。手写代码最终看起来像: fn handwriting_b_an_star(input: &str) -> bool { let bytes = input.as_bytes();让 mut pos = 0; if pos == bytes.len() || bytes[pos] != b'b' { 返回 false; } pos += 1; while pos < bytes.len() { if bytes[pos] != b'a' { return false; } } pos += 1; if pos == bytes.len() || bytes[pos] != b'n' { 返回 false; } pos += 1; (有多种方法可以优化此代码并使其更快,但就我们的目的而言,它可以作为一个很好的比较)当我针对这两个示例对几个示例进行基准测试时,我发现手写版本比解释器快 10-20 倍。显然还有很大的改进空间。现在让我们看看如何使用 JIT 编译来获得性能与手写版本一样的通用正则表达式引擎。如何进行 JIT 编译 JIT 编译代码有两个步骤。首先,为要运行的代码生成程序集。获得代码后,您可以将汇编代码打包到一个函数中,您可以像程序中的任何其他代码一样调用该函数。为了生成程序集,我们将使用称为复制和修补的方法的变体。我们的想法是,我们在汇编中拥有一系列模板,用于我们想要进行 JIT 编译的不同操作。这些模板称为“模板”。当我们想要 JIT 编译时
这篇文章对您有帮助吗?

订阅66必读

每日精选科技资讯,直达你的邮箱