为了提升php的性能,php8支持了JIT。
Just In Time (JIT), 当 JIT 按预期工作时,您的代码不会通过 Zend VM 执行,而是作为一组 CPU 级指令直接执行。
但是为了更好地理解它,我们需要考虑 php 如何在内部工作。不是很复杂,但需要一些介绍。PHP 的代码是怎么执行的?
总所周知, PHP 是解释型语言,但这句话本身是什么意思呢?
每次执行 PHP 代码(命令行脚本或者 WEB 应用)时,都要经过 PHP 解释器。最常用的是 PHP-FPM 和 CLI 解释器。
解释器的工作很简单:接收 PHP 代码,对其进行解释,然后返回结果。
一般的解释型语言都是这个流程。有些语言可能会减少几个步骤,但总体的思路相同。在 PHP 中,这个流程如下:
读取 PHP 代码并将其解释为一组称为 Tokens 的关键字。这个过程让解释器知道各个程序都写了哪些代码。 这一步称为 Lexing 或 Tokenizing 。
拿到 Tokens 集合以后,PHP 解释器将尝试解析他们。通过称之为 Parsing 的过程生成抽象语法树(AST)。这里 AST 是一个节点集表示要执行哪些操作。比如,「 echo 1 + 1 」实际含义是 「打印 1 + 1 的结果」 或者更详细的说 「打印一个操作,这个操作是 1 + 1」。
有了 AST ,可以更轻松地理解操作和优先级。将抽象语法树转换成可以被 CPU 执行的操作需要一个用于过渡的表达式 (IR),在 PHP 中我们称之为 Opcodes 。将 AST 转换为 Opcodes 的过程称为 compilation 。
有了 Opcodes ,有趣的部分就来了: executing 代码! PHP 有一个称为 Zend VM 的引擎,该引擎能够接收一系列 Opcodes 并执行它们。执行所有 Opcodes 后, Zend VM 就会将该程序终止。
这是包含 Opcache 扩展的流程示意图:
如果说 Opcache 扩展可以更快的获取 Opcodes 将其直接转到 Zend VM,则 JIT 让它们完全不使用 Zend VM 即可运行。
Zend VM 是用 C 编写的程序,充当 Opcodes 和 CPU 之间的一层。 JIT 在运行时直接生成编译后的代码,因此 PHP 可以跳过 Zend VM 并直接被 CPU 执行。 从理论上说,性能会更好。
jit执行流程图如下:
这听起来很奇怪,因为在编译成机器码之前,需要为每种类型的结构体编写一个具体的实现。但实际上这也是合理的。
PHP 的 JIT 使用了名为 DynASM (Dynamic Assembler) 的库,该库将一种特定格式的一组 CPU 指令映射为许多不同 CPU 类型的汇编代码。因此,编译器只需要使用 DynASM 就可以将 Opcodes 转换为特定结构体的机器码。
如果预加载能够在执行之前将 PHP 代码解析为 Opcodes,并且 DynASM 可以将 Opcodes 编译为机器码 (Just In Time 编译) ,为什么我们不立即使用运行前编译 (Ahead of Time 编译) 立即编译 PHP 呢?原因之一就是 PHP 是弱类型语言,这意味着在 Zend VM 尝试执行某个操作码之前, PHP 通常不知道变量的类型。
使用jit和未使用jit的效率对比
所以php jit技术能够提高php的执行效率。
网友回复