PHP为什么慢?
PHP的慢是相对于C/C++级别的语言来说,事实上,PHP语言最初的设计,就不是用来解决计算密集型的应用场景。我们可以这样粗略理解为,PHP为了提升开发效率,而牺牲了执行效率。(推荐学习:PHP编程从入门到精通)
我们知道PHP一个很大的特点,就是弱类型特性,也就是说,我可以随意定义一个变量,然后给它随意赋值为各种类型的数据。以一个int整型数字为例子,在C语言中:
int num = 200;//通常是4字节
但是,如果是PHP定义了一个同样的变量,实际对应的存储结构则是:
这个结构体将会占据远比C变量多得多的内存,PHP中定义方式如下:
$a = 200;//这变量将实际占用对比C变量很多倍的存储空间。
其实对PHP来说,无论存储什么类型的数据,都是用上述“通杀”的结构体实现。为了兼容PHP程序员的变量类型“乱入”,PHP做到了对开发者的友好,但是对执行引擎很残酷。单个变量内存消耗可能还不明显,一旦用到PHP的数组等,则复杂度指数上升(数组的实现是HashTable)。
然后,Zend引擎执行时,将这些PHP代码编译为opcode(PHP的中间字节码,格式有点类似于汇编),由Zend引擎逐行解释执行。
无论是字符串的连接操作,还是数组的简单修改等,几乎都是“PHP程序员一句话,Zend引擎跑断腿”的节奏。因此,同样的操作,对比C来说,PHP消耗了更多的CPU和内存等系统资源。除此之外,还有内存自动回收、变量类型判断等等,都会增加系统资源的消耗。
例如,我用纯PHP实现的快速排序函数和原生sort函数,排序10000个整型数字,来做一个耗时对比,结果如下:
原生的sort耗时3.44 ms,而我们自己实现的PHP函数sort则是68.79 ms。我们发现,两者执行效率差距巨大。
我的测试方式,是计算函数执行前后的时间间隔,而不是整个PHP脚本从启动到结束的时间。PHP脚本启动和关闭过程,本身有着一系列的初始化和清理工作,也会占据不少的耗时。
通常情况下,PHP执行效率的排行是:
最快的是PHP语言结构(isset、echo等),PHP语言的一部分(它们根本不是函数)。
然后比较快的就是PHP的原生和拓展函数。PHP拓展,基于Zend API之上,用C实现的功能,执行效率和C++/Java是属于同一个数量级的。
真正慢的就是,我们通过PHP自己写的代码和函数。例如,假如我们使用的比较重的纯PHP实现的框架,因为框架本身的模块很多,所以,会明显拖累语言层面的执行效率,同时占据更多的内存。(国内的Yaf框架,以拓展的方式实现,因此执行效率远快于纯PHP写的框架)
在一般情况下,我们并不推荐用过PHP实现逻辑复杂计算类型的功能,尤其是Web系统流量比较大的场景下。因此,PHP程序员应该对PHP的各种原生函数和各类拓展有一个比较广泛的了解,在具体的功能实现场景中,寻求更原生的解决方案(原生接口或者拓展),而不是自己写一堆复杂的PHP代码来实现这类型功能。
如果有足够的PHP拓展开发实力,将这类型业务功能重写为一个PHP拓展,也会大幅提升代码的执行效率。这是一个非常不错的方式,也被广泛应用PHP优化中。但是,自己编写的PHP业务拓展的缺点也很明显:
拓展开发耗时比较长,需求变更的时候修改也复杂,写得不好可能会影响Web服务稳定性。(例如,在Apache的worker模式下,多线程场景下挂掉,会影响同一个进程下的其他正常子线程。如果是多线程的Web模式,编写拓展还需要支持线程安全)
拓展在PHP版本升级的时候,可能需要做额外的兼容工作。
人员变动后的维护和接手成本也比较高。
实际上,在互联网一线企业中,更常见的解决方案,并非增加PHP拓展,而用C/C++独立写一个服务server,然后PHP通过socket和服务server通信来完成业务处理,并不将PHP本身和业务耦合在一起。
不过,Web服务大部分的性能瓶颈都在网络传输和其他服务server的耗时上(例如MySQL等),PHP执行的耗时在整体耗时的占用比例非常小,所以从业务角度来说,影响可能并不明显。
Atas ialah kandungan terperinci php为什么慢. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!