1.什么是opcode缓存?
当解释器完成对脚本代码的分析后,便将它们生成可以直接运行的中间代码,也称为操作码(Operate Code,opcode)。Opcode cache的目地是避免重复编译,减少CPU和内存开销。如果动态内容的性能瓶颈不在于CPU和内存,而在于I/O操作,比如数据库查询带来的磁盘I/O开销,那么opcode cache的性能提升是非常有限的。但是既然opcode cache能带来CPU和内存开销的降低,这总归是好事。
现代操作码缓存器(Optimizer+,APC2.0+,其他)使用共享内存进行存储,并且可以直接从中执行文件,而不用在执行前“反序列化”代码。这将带来显着的性能加速,通常降低了整体服务器的内存消耗,而且很少有缺点。
2.为什么要使用Opcode缓存?
这得从PHP代码的生命周期说起,请求PHP脚本时,会经过五个步骤,如下图所示:
Zend引擎必须从文件系统读取文件、扫描其词典和表达式、解析文件、创建要执行的计算机代码(称为Opcode),最后执行Opcode。每一次请求PHP脚本都会执行一遍以上步骤,如果PHP源代码没有变化,那么Opcode也不会变化,显然没有必要每次都重行生成Opcode,结合在Web中无所不在的缓存机制,我们可以把Opcode缓存下来,以后直接访问缓存的Opcode岂不是更快,启用Opcode缓存之后的流程图如下所示:
3.有那些PHP Opcode缓存插件?
Optimizer+(Optimizer+于2013年3月中旬改名为Opcache,PHP 5.5集成Opcache,其他的会不会消失?)、eAccelerator、xcache、APC …
4.PHP Opcode原理
Opcode是一种PHP脚本编译后的中间语言,就像Java的ByteCode,或者.NET的MSL。PHP执行这段代码会经过如下4个步骤(确切的来说,应该是PHP的语言引擎Zend)
1.Scanning(Lexing) ,将PHP代码转换为语言片段(Tokens)
2.Parsing, 将Tokens转换成简单而有意义的表达式
3.Compilation, 将表达式编译成Opcodes
4.Execution, 顺次执行Opcodes,每次一条,从而实现PHP脚本的功能。
扫描 -> 解析 -> 编译 -> 执行 -> 输出
执行步骤
- 扫描 对代码进行词法和语法分析,将内容切割成一个个片段 (token)
- 解析 将代码片段筛掉空格注释等,将剩下的token 转成有意义的表达式
- 编译 将表达式编译成中间码 (opcode)
- 执行 将中间码一条条执行
- 输出 将执行结果输出到缓冲区
PHP4.2开始提供了一个函数叫token_get_all,这个函数就可以讲一段PHP代码 Scanning成Tokens;
<?php
$code = <<<EOF
<?php
echo 'hello world'l;
$data = 1+1;
echo $data;
EOF;
print_r(token_get_all($code));
执行结果
Array
(
[0] => Array
(
[0] => 376
[1] => <?php
[2] => 1
)
[1] => Array
(
[0] => 319
[1] => echo
[2] => 2
)
[2] => Array
(
[0] => 379
[1] =>
[2] => 2
)
[3] => Array
(
[0] => 318
[1] => 'hello world'
[2] => 2
)
[4] => Array
(
[0] => 310
[1] => l
[2] => 2
)
[5] => ;
[6] => Array
(
[0] => 379
[1] =>
[2] => 2
)
[7] => =
[8] => Array
(
[0] => 379
[1] =>
[2] => 3
)
[9] => Array
(
[0] => 308
[1] => 1
[2] => 3
)
[10] => +
[11] => Array
(
[0] => 308
[1] => 1
[2] => 3
)
[12] => ;
[13] => Array
(
[0] => 379
[1] =>
[2] => 3
)
[14] => Array
(
[0] => 319
[1] => echo
[2] => 4
)
[15] => Array
(
[0] => 379
[1] =>
[2] => 4
)
[16] => ;
)
观察上面可以得到三个信息
- Token id 例如空格回车都是 379
- token 字符串
- 行号
Token id 是Zend内部token对应码, 定义于zend_language_parser.h
提高PHP执行效率
- 压缩代码,去除无用注释和空白字符 (jquery.min.js)
- 尽量使用PHP内置函数或扩展函数
- 用 apc/xcache/opcache 等缓存PHP的opcode
- 缓存复杂和耗时的运算结果
- 能异步处理的不要同步处理,如发送邮件
没有安装OPcache
同样的接口从以前的几百毫秒提升到现在的50ms左右
HHVM 为何速度快
HHVM 是由 Facebook 打造的 PHP 虚拟机,它通过将 PHP 代码动态翻译成原生机器码而大幅提高速度。执行时不用每次都去解析。