鸟哥本次分享的主要内容是,在php7发布的这两年期间他们的主要工作,包括release的7.1和正在开发中的jit分支。说实话,由于本人水平有限,鸟哥分享的内容只能大概听懂意思,知道他们在做什么,但具体原理细节,鸟哥分享的我还真听不懂。这里就对鸟哥的分享内容做个总结。

php7之后还有什么?JIT

php7于15年正式发布,他的最大卖点是,无感知的100%性能提升,包含了运行速度与内存消耗。那么在此之后php该往哪里发展呢?目前已经在开发的一个大方向就是JIT

JIT是什么?为什么是JIT?
鸟哥并没有做过多的解释。我就谈一些我的肤浅认识,给phper们提供些参考。

首先JIT(just in time)并非是新技术,一大批语言如java早已实现。JIT的思想很简单,即在程序运行时动态对程序进行编译,生成平台相关的机器码,从而加快程序运行速度。

php文件的执行流程大致是首先引擎加载php文件,解释器逐条解释执行代码。引入JIT后,前面一样,重点是JIT编译器会根据Runtime信息对热点代码进行动态编译生成机器码,然后这部分代码以后就可以直接执行了,而不需要解释器逐条解释执行了,运行效率便得到了提升

看到这里不知道大家是否和我有一样的疑问,既然编译为机器码执行的效率那么高,为何不在项目正式部署前全部进行编译,何必在运行时编译?要知道运行时编译也会增加程序的执行时间的。我在查阅了一些资料和一番思考后,有以下一些浅见

代码发布前先编译,是比JIT更早的通用办法,称为AOT(ahead of time),c语言便是这种执行模式。关于这两种模式孰优孰劣,学术界一直争论不休,目前也没有定论。但JIT相比AOT有这样几个优点

  • 发布速度快。不用每次都编译,发布速度自然快
  • 优化效率更好。因为JIT是基于Runtime信息,比AOT更“了解”代码,优化的效率更好。比如分析Runtime得知某个变量虽然声明是10个字节,但运行过程中一直是1个字节,那么就可以减小程序内存消耗;再比如某段代码始终未被执行,JIT则可以直接将其忽略
  • 粒度更精细。JIT可以只针对hotspot(热点)进行编译,热点可能是一个函数或者只是一个代码段
  • 对码农透明。JIT无须码农自己对程序根据不同平台进行编译发布,只需要写高级代码即可

基于以上几个优点,再结合php一贯的简单易用原则,我想JIT确实是不错的选择。不过php也是支持AOT的,有兴趣的同学可以查一下。

但JIT技术也绝不是灵丹妙药,即便是编译也是需要时间的,当代码编译的时间消耗大于运行收益时,程序反而会变慢!会有这种情况吗?有的,比如某个项目中,热点并不明显,JIT编译的代码执行次数都很少,那么编译带来的收益是有可能小于编译本身的消耗的

以下是在标准测试中引入JIT技术后,php运行效率比7.2有100%的性能提升,不过在实际生产环境中效果不会有这么好

php7.1做了什么?类型预测

php要想实现JIT,有一个难题必须解决,那就是变量的类型预测。试想如果在动态编译时还要进行大量的类型检查,性能将会大打折扣。php7中已经可以对变量类型进行控制,7.1则是更加完善了这个机制,可以说目前php已经是半强类型语言了。但由于php的弱类型历史,仍有大量代码运行前是无法得知变量类型的,所以在7.1中鸟哥进行了大量变量类型预测的工作,为后续JIT打基础

变量预测
比较简单的一种办法是数据流分析,即分析代码的上下文,推断出变量的可能类型,比如

1
2
3
4
5
6
7
8
9
function calc ($a1, $b2) {        // $a1: [ANY], $b2: [ANY]
$T3 = $a1 * 2; // $T3: [LONG, DOUBLE]
$a4 = $T3 % 1000; // $a4: [LONG]
$T5 = $b2 * 3; // $T5: [LONG, DOUBLE]
$b6 = $T5 % 1000; // $b6: [LONG]
$T7 = $a4 + $b6; // $T7: [LONG, DOUBLE]
return $T7;
}

其实这还是很困难的,鸟哥列举了一些开发过程中遇到的困难。比如变量的变量,$$var_name,或者顶层代码(即写在函数和类之外的代码)等等。php的历史包袱还是很重的。解决这些问题的简单办法就是强类型,但这又会降低开发效率,因为优化而影响phper的开发效率这是鸟哥所不愿意的,他认为业务永远是优先的,优化只是支线

目前鸟哥的解决办法就是对JIT进行分级,通过配置实现不同程度的动态编译,从而降低类型预测的难度。另外就是针对具体的场景,进行垂直优化

问答环节

鸟哥的问答环节也非常精彩,原定一小时的分享最终超了一小时,下面我就凭着记忆对一些问题复现一下,可能存在偏差,将来我可不负责

php7.1那个诡异的函数返回类型限定是如何考虑的?
鸟哥:没什么特别考虑,投票投出来的。首先说明一点,我投的是反对票。包括php的命名空间反斜杠我也是非常反对的,但可能由于我并没有对这方面太深的认识,没有理解其他开发者的意图。不过这些问题用习惯了也不是什么大的问题

升级php7后,遇到了一个诡异的引用计数的问题。具体记不清了,大致是他们发现有个应该回收的变量在升级后没有回收
鸟哥:我现在不能给你准确答复,有可能是个bug,这个我随后跟进一下。但我想说的是你刚才介绍了你们在调试过程中对引用数的反复推算,其实不必纠结这,引用数用于垃圾回收时只有0和非0两种区别,我们在增加引用计数时可能有时候不是加1,而是加2,所以不要太在意具体是多少,确定大于0就行

一位学生提问者表示自己对高并发、分布式感兴趣,如何提升这方面的技能呢?
鸟哥:这里你有一个误区。我们研究学习技术并不是为了学习而学习,而是为了解决实际的业务问题。你没有接触过这方面的业务,自然没有这方面的经验,等你真正有这个业务需求时,好多东西原理都很简单,使用方法也很成熟,自然就会了,这是个水到渠成的过程,不必刻意去追求那个“术”。另外,我多说一句是,其实当你真正处在这样的业务中时,你会发现这些事情很少需要你操心的,OP通过各种集群就已经把这些问题给屏蔽了。

鸟哥你是怎样看待php的前景呢?现在黑php的这么多人
鸟哥:php的前景不要问我,要问你和我,整个php生态。天峰贡献一个swoole,php就有了高性能网络请求功能,xx贡献个php-ml,php就有了大数据处理功能,我今天贡献一个jit,php就有了动态编译能力。php发展到今天就是大家你一个小贡献,他一个小贡献积累出来的,所以php的前景好不好,要看我们生态,也希望大家踊跃贡献。至于黑php,我现在都懒得反驳了,有句话说的好,“黑php之前,先数数他给你挣了多少钱”,我一直认为业务是技术存在的理由,能不能快速响应需求、实现业务才是最根本的。

目前php没有连接池,非常不方便,不知道官方是否有支持计划?
鸟哥:目前没有。不过这不正是一个给社区做贡献的机会吗?你们开发一个连接池,贡献到社区既方便了自己,也方便了大家。天峰昨天的分享PHP-X,不就是为了这样的事

鸟哥你是怎样看待全栈工程师这个概念的?
鸟哥:我并不认同这个概念,我认为这是个伪命题。全栈这个概念最早是前端工程师提出来的,认为从前端到后端这是“全栈”,但我理解的全栈应该是对一个领域从底层原理到上层应用,这不才更应该叫做栈?自称全栈工程师的大部分属于只对各个领域多少有些认识而已。优秀的工程师不必刻意去追求全栈,你只需要在你的领域里不断深入就行,深度达到了,自然就有了广度,广度是深度的副产品,推而广之,就是所谓的全栈工程师是当你在一个领域深入到一定阶段后的副产品,而不是刻意在各个领域学出来的

php7对性能压榨已经比较彻底了,未来php是继续提高性能呢,还是增加新的特性?
鸟哥:你想太多了,目前并未任何打算。JIT开发就非常困难了,这个是否能够成功还是未知数,下次大会如果JIT没有完成,我就没啥可分享的了。

现在在北京很难安家,将来回到二三线城市,php很难找工作,不知道鸟哥有什么看法吗?
鸟哥:不必过于担心,不光是程序猿,其实还有好多公司也很难承受一线城市的成本,也在不断的往二三城市分流,所以找工作问题还是不大的。另外至于你担心php难找工作,那你可以换java、换go啊,一个程序猿不应该给自己打上标签,“xx程序猿”,你作为一个工程师,至少要精通3种以上的语言,而且要有良好的学习能力

鸟哥你是如何放松你的部下呢?会请他们去大保健吗?
鸟哥:这个我没太多经验,不过就我自己来说,有时候加班多了还是比较累的,我有段时间脖子特别疼,一周得去至少三次按摩院按摩才能缓解,当然我说的是盲人按摩。后来我真的研究了颈椎康复指南,不是开玩笑,我是真研究了。人的脑袋大概12斤重,你想你整天顶个西瓜,要是颈椎肌肉不行的话,能不难受吗?所以我后来经常去健身房,锻炼颈椎,后来才慢慢好了