共计 1885 个字符,预计需要花费 5 分钟才能阅读完成。
在开发过程中发现,用 require 来加载一个很大(几百 K,甚至几兆)的配置文件时,会造成响应超时。如果把这个配置文件的内容序列化后,用 file_get_contents 获取文件然后反序列化的方法来加载,就会快很多。
经过近两周的研究,大概知道了其中的原因。
首先,还从 PHP 的流程说起,PHP 其实有两个流程,一个是启动的流程,一个是响应请求的流程。PHP 作为 Apache 的一个模块,向 Apache 注册了两个函数,一个是 Aapche 启动的时候运行的函数:sapi_startup;一个是 Apache 接收到请求的时候调用的函数:php_handler
启动的流程:
Apache 启动
-> sapi_startup
-> php_module_startup (PHP 启动总开关)
-> zend_startup (启动 Zend 引擎,包括初始化全局变量,初始化 compile 和 execute 函数
相应请求的流程:
Apache 收到请求
-> sapi_startup
-> zend_activate (包括初始化编译器、初始化执行器、启动扫描器)
-> zend_compiler (语法分析、语意分析、生成 opcode)
-> zend_execute (执行每个 opcode)
-> zend_deactive(清理本次请求用到的数据)
如果遇到 require 或者 include 之类的函数时,会 从 zend_execute 阶段重新回到 zend_compiler 阶段,开始解释 PHP,执行 PHP 的过程。
除了 zend_compiler 和 zend_execute 阶段之外,require 和 file_get_contents 的开销基本是一样的。
而且我们服务器上安装了 apc 扩展,就是说 zend_compiler 阶段可以认为两者也是一样的。
那他们的性能九差在 zend_execute 阶段了。
首先,让我们用 vld 扩展查看一下两个文件生成的 opcode 的数量,因为这个是 execute 的输入。
结果显示,require 生成的 opcode 数量为 2 万多个,大多是 ADD_ARRAY_ELEMENT,就是构造数据;而 file_get_contents 生成的 opcode 只有 6 个;
然后再来对比执行的效率:
这两个函数的执行可以分成两部分:读取文件和构造配置文件里面的数组;
先说读取文件,require 读取的机制是,以 8192 字节大小的 buffer 循环将文件读入内存;而 file_get_contents 使用的是 mmap,直接将文件映射到了虚拟内存当中。这样的话,require 会比 file_get_contents 多出大量的系统调用。而 file_get_contents 无需作这么多用户态和内核态的切换工作。这一步,file_get_contents 胜出一筹;
再来看构造数组,require 构造的机制是生成 2 万多个 opcode,然后一次执行这些 opcode;而 file_get_contents 使用的是 unserialize 函数,他对传入的文本进行解析,然后逐级构造成数组。他们构造数组的思路是一样的,但是 require 每增加一级数据的开销要比 unserialize 大;这一局也是 file_get_contents 略优;
但是,file_get_contents 在 PHP 内部是函数调用,而 require 是一个内置的 opcode,所以调用 file_get_contents 时的开销要比 require 略大;
所以,小文件的时候,file_get_contents 读取文件时 内存映射的优势发挥不出来,两者部分伯仲;大文件的时候,由于 require 要 2K2K 的循环调用 read 系统调用,就降低了他的性能。
CentOS 6.3 安装 LNMP (PHP 5.4,MyySQL5.6) http://www.linuxidc.com/Linux/2013-04/82069.htm
在部署 LNMP 的时候遇到 Nginx 启动失败的 2 个问题 http://www.linuxidc.com/Linux/2013-03/81120.htm
Ubuntu 安装 Nginx php5-fpm MySQL(LNMP 环境搭建) http://www.linuxidc.com/Linux/2012-10/72458.htm
《细说 PHP》高清扫描 PDF+ 光盘源码 + 全套教学视频 http://www.linuxidc.com/Linux/2014-03/97536.htm
PHP 的详细介绍 :请点这里
PHP 的下载地址 :请点这里