PHP 8的即时编译器是Opcache扩展的一部分,旨在在运行时将某些操作码编译为CPU指令。

这意味着使用JIT,Zend VM不需要解释某些操作码,并且这些指令将直接作为CPU级指令执行。

PHP 8的JIT

PHP 8将带来的最受评论的功能之一是Just In Time(JIT)编译器。许多博客和社区都在谈论它,并且肯定会引起很大的轰动,但是到目前为止,我发现关于JIT应该做什么的细节很少。

经过多次研究和放弃后,我决定亲自检查PHP源代码。结合我对C语言的一点了解以及到目前为止所收集的所有分散信息,我提出了这篇文章,希望它也可以帮助您更好地理解PHP的JIT。

简化了事情:当JIT按预期工作时,您的代码将不会通过Zend VM执行,而是直接作为一组CPU级指令执行。

这就是整个想法。

但是要更好地理解它,我们需要考虑php在内部如何工作。不是很复杂,但是需要一些介绍。

我写了一篇博客文章,其中概述了php的工作原理。如果您认为此处的帖子太过密集,则只需检查另一个即可,稍后再回来。事情变得更容易理解。

PHP代码如何执行?

我们都知道php是一种解释语言。但这到底是什么意思?

每当您要执行PHP代码时(无论是代码段还是整个Web应用程序),都必须通过php解释器。最常用的是PHP FPM和CLI解释器。

他们的工作非常简单:接收php代码,对其进行解释,然后将结果返回回去。

通常,每种解释语言都会发生这种情况。有些人可能会删除一些步骤,但总体思路是相同的。在PHP中,它是这样的:

读取PHP代码并将其转换为一组称为Token的关键字。通过此过程,解释器可以了解在程序的哪个部分中编写了哪些代码。第一步称为Lexing或Tokenizing。

有了令牌,PHP解释器将分析此令牌集合并尝试使它们有意义。结果,通过称为解析的过程生成了抽象语法树(AST)。此AST是一组节点,指示应执行哪些操作。例如,“ echo 1 +1”实际上应表示“打印1 +1的结果”或更实际地是“打印操作,该操作为1 +1”。

例如,借助AST,可以更轻松地了解操作和优先级。将这棵树转换成可以执行的东西需要一个中间表示(IR),在PHP中我们称之为操作码。将AST转换为操作码的过程称为编译。

现在,有了Opcodes便是有趣的部分:执行代码!PHP具有称为Zend VM的引擎,该引擎能够接收操作码列表并执行它们。执行所有操作码后,Zend VM存在并且该程序终止。

我有一个图表,可以让您更加清楚:

有关PHP解释流程的简化概述。

如您所见,很简单。但是这里有一个瓶颈:如果您的php代码可能不会经常更改,那么每次执行代码时对其进行词法分析和解析有什么意义?

最后,我们只关心操作码,对吗?对!这就是存在Opcache扩展的原因。

Opcache扩展

Opcache扩展是PHP附带的,通常没有太大的理由要停用它。如果使用PHP,则可能应该打开Opcache。

它的作用是为操作码添加一个内存共享缓存层。它的工作是从AST中提取新生成的操作码并将其缓存,以便进一步执行可以轻松地跳过词法分析和语法分析阶段。

这是考虑了Opcache扩展的流程示意图:

PHP使用Opcache的解释流程。如果文件已经被解析,则php会为其获取缓存的操作码,而不是再次解析。

惊讶地看到它如何精美地跳过了Lexing,解析和编译步骤iling。

旁注:这就是PHP 7.4的预加载功能大放异彩的地方!它使您可以告诉PHP FPM解析代码库,将其转换为操作码并甚至在执行任何操作之前就将其缓存。

您可能想知道JIT的位置,对吗?我希望如此,这就是为什么我要写这篇文章的原因……

即时编译器有效地做什么?

在听完PHP Internals News的PHP和JIT播客专题节目中的Zeev的解释后,我对JIT的实际用途有了一些了解。

如果Opcache使获取操作码的速度更快,以便它们可以直接转到Zend VM,则应该使用JIT使它们完全在没有Zend VM的情况下运行。

Zend VM是用C编写的程序,充当操作码和CPU本身之间的一层。JIT的作用是在运行时生成编译的代码,因此php可以跳过Zend VM并直接进入CPU。从理论上讲,我们应该从中获得性能。

起初,这听起来很奇怪,因为要编译机器代码,您需要为每种类型的体系结构编写一个非常具体的实现。但实际上这是很合理的。

PHP的JIT实现使用名为DynASM(动态汇编程序)的库,该库将一种特定格式的一组CPU指令映射为许多不同CPU类型的汇编代码。因此,即时编译器使用DynASM将操作码转换为特定于体系结构的机器代码。

但是,有一个想法困扰了我很多时间了……

如果预加载能够在执行之前将php代码解析为操作码,并且DynASM可以将操作码编译为机器代码(及时编译),那为什么我们不立即使用Ahead of Time编译立即编译PHP?

通过听Zeev的一集,我得到的线索之一就是PHP的类型很弱,这意味着PHP通常在Zend VM尝试执行某个操作码之前才知道变量的类型。

通过查看zend_value联合类型,可以看出这一点,该类型具有许多指向变量的不同类型表示形式的指针。每当Zend VM尝试从zend_value中获取值时,它都会使用ZSTR_VAL之类的宏来尝试从值联合访问字符串指针。

例如,该Zend VM处理程序应处理“更小或等于”(<=)表达式。看一下它如何分支到许多不同的代码路径中,只是为了猜测操作数类型。

用机器代码复制这种类型推断逻辑是不可行的,并且可能使事情变得更慢。

在对类型进行求值后编译所有内容也不是一个好选择,因为编译为机器代码是一项占用大量CPU的任务。因此,在运行时编译所有内容也是不好的。

即时编译器的行为如何?

现在我们知道我们无法推断类型来生成足够好的提前编译。我们也知道在运行时进行编译很昂贵。JIT对PHP有何好处?

为了平衡此等式,PHP的JIT尝试仅编译一些认为可以产生回报的操作码。为此,它将分析Zend VM正在执行的操作码,并检查哪些代码可能有意义。(根据您的配置)

编译某个操作码后,它将把执行委派给该已编译代码,而不是委派给Zend VM。看起来如下:

PHP的JIT解释流程。如果已编译,则操作码不会通过Zend VM执行。

因此,在Opcache扩展中,有两条指令可检测是否应编译某个Opcode。如果是,则编译器然后使用DynASM将此操作码转换为机器代码,并执行此新生成的机器代码。

有趣的是,由于当前实现中已编译的代码以兆字节为单位(也是可配置的),因此代码执行必须能够在JIT和解释的代码之间无缝切换。

我仍不确定编译部分何时有效进行,但我想我现在暂时不想知道。

因此,您的性能提升可能不会很大

我希望现在更加清楚,为什么每个人都在说大多数php应用程序不会因为使用Just In Time编译器而获得巨大的性能优势。为什么Zeev建议为您的应用程序分析和试验不同的JIT配置是最好的方法。

如果使用PHP FPM,通常将在多个请求之间共享已编译的操作码,但这仍然不能改变游戏规则。

这是因为JIT优化了CPU约束的操作,并且当今大多数php应用程序都比任何东西受I / O约束更多。不管是否要访问磁盘或网络,处理操作是否已编译都没有关系。时间将非常相似。

除非…

您正在执行不受I / O约束的操作,例如图像处理或机器学习。任何不接触I / O的东西都将从“即时编译器”中受益。

这也是为什么人们现在说我们更愿意编写用PHP而不是C编写的本机PHP函数的原因。如果仍然编译此类函数,则开销将无法表达。

程序员的欢乐时光……

php 8 jit,了解PHP 8的JIT相关推荐

  1. JIT编译器杂谈#1:JIT编译器的血缘(一)

    这年头啥都得讲个娱乐性.专栏第一篇杂谈,先来点八卦轻松一下. 对我来说,有没有人最近用DJI无人机求婚成功啥的如同耳边一阵风:上周CoreCLR在GitHub上以MIT许可证开源了才是激动人心的娱乐新 ...

  2. java全jit编译_Javac编译与JIT编译

    词法分析是将源代码的字符流转变为标记(Token)集合.单个字符是程序编写过程中的的最小元素,而标记则是编译过程的最小元素,关键字.变量名.字面量.运算符等都可以成为标记,比如整型标志int由三个字符 ...

  3. jit编译_意外分配– JIT编译抖动

    jit编译 在研究ByteWatcher时 (请参阅我的上一篇 文章 ),我遇到了一些非常奇怪的事情. 这是实际的代码段,用于找出特定线程上的分配量: return (long) mBeanServe ...

  4. java jit技术_如何理解JIT编译技术?

    JIT,就是JUST IN TIME的缩写,在计算机技术体系内,JIT指一种动态编译(Dynamic Compilation)技术. 先解释几个概念: 解释(Interpreter):解释就是把源程序 ...

  5. 什么是JIT,JDK17移除了JIT?

    前言 各大官号发布关于JDK17的文章中都提到了JDK17的变动中移除了实验性的AOT与JIT ,AOT就不说了吧,无关紧要的感觉.但是其中并没有说明什么是实验性的JIT,本文在此做一个自己的解释. ...

  6. php 8 jit,理解 PHP 8 的 JIT

    TL;DR PHP 8 的 JIT(Just In Time)编译器将做为扩展集成到 php 中 Opcache 扩展 用于运行时将某些操做码直接转换为从 cpu 指令.php 这意味着使用 JIT ...

  7. 在C++中使用LLVM的JIT功能进行代码优化:Optimization passes--PassManagerBuilder

    今天找了一天的在LLVM中如何进行代码优化的方法. 一开始在谷歌搜索LLVM JIT,看到了LLVM的官方教程: 1. Building a JIT: Starting out with Kaleid ...

  8. (超级详细)jit的介绍和用法

    文章目录 前言 编译模式 Lazy compilation Eager compilation 编译选项 nopython object 补充 问题1 问题2 一个坑 参考 前言 jit是numba库 ...

  9. Java 性能优化系列之3.2[JVM调优] --- JIT即时编译

    参考:http://blog.csdn.net/oscar999/article/details/47271531            http://taogebx.iteye.com/blog/9 ...

最新文章

  1. Conv1D和Conv2D的区别
  2. 山西流感就诊比持续上升 专家为民答疑解惑
  3. Android登录拦截器实现方式(二)
  4. docker 核心概念整理
  5. yum国内网络源的架设
  6. 从外到内提高SQL Server数据库性能
  7. 关于 mldonkey 的一些讨论和设置
  8. 【LeetCode笔记】263. 丑数(Java、迭代)
  9. thinkPhp 3.1.3的验证码无法显示的问题
  10. 本地Windows安装MySQL
  11. nxlog以syslog方式发送日志
  12. 买手机是不是主要看处理器?
  13. Android Studio 中使用 Git
  14. 2021-2022年度“扣哒杯”AI世青赛初赛落下帷幕
  15. localhost无法访问
  16. 学日语小技巧 让Office Word效劳
  17. word设置章标题与节标题
  18. Go语言爱好者周刊:第 14 期
  19. Zookeeper(五)Watcher机制
  20. MySQL单表查询练习题

热门文章

  1. 过拟合、正则化和损失函数
  2. 从疝气病症预测病马是否能够存活
  3. Android使用ttf字体库替代替图片
  4. 喜报!《大数据》72篇论文入选中国知网《学术精要数据库》高影响力论文!...
  5. 人一辈子最怕留下的25个遗憾
  6. 乐视奥比中光深度相机在下其官网下载openni配置后运行例子出现 D: 640x400,C: 640x480错误
  7. Linux虚拟化技术
  8. ES6的扩展运算符 [...arr]
  9. iOS4.3导致iPhone续航能力下降
  10. 第七章 实现炫酷效果—图像和动画(1)