澳门新浦京手机版告诉你如何优化php代码 让速度提升5倍以上

程序员都喜欢最新的PHP
7,因为它使PHP成为执行最快的脚本语言之一(参考PHP 7 vs HHVM
比较)。但是保持最佳性能不仅需要快速执行代码,更需要我们知道影响性能的问题点,以及这些问题的解决方案。本文涵盖了保障PHP应用平稳高速运行的所有知识点,大量干货来袭,强烈建议收藏。

网页访问速度的提升,是可以通过代码的优化来实现的。代码的优化,并不是说代码越少越好,而是主要看代码的运行能力和执行效率,看其消耗CPU和内存的多少。例如Facebook近来就宣布通过代码优化而将网站性能提高了一倍,平均访问时间从5s降至2.5s,这个结果无疑是极其诱人的。

澳门新浦京手机版 1

PHP是一门很多人正在使用的语言,在网站开发上PHP的使用广泛度超过ASP和ASP.NET,看看时下流行的CMS和博客用什么语言来开发的就知道了。

一、我们可以且应该优化什么?

PHP简史

PHP是由拉斯姆斯·勒多夫于1995年开始开发的。起初,它只是勒多夫为了要维护个人网页,而用c语言开发的一些CGI工具程序集,我们从PHP这个缩写最初的来源“Personal
Home
Page”(个人主页)就可以看出这一点。然而,随着勒多夫不断地扩充它的功能,PHP逐渐成为了现在的“PHP:超文本预处理器”。

在过去的20年中,PHP的开发团队一直致力于提升PHP的性能,最引人瞩目的是于1999年引入的Zend语法解释器引擎。2000年发布的PHP
4,包含了一个內建的编译器和执行器模型,使得PHP开始有能力开发动态的Web应用。2015年PHP发布了里程碑式的版本PHP
7.0,极大的提升了Zend引擎的性能,并降低了PHP的整体内存使用率。截止到本文发稿为止,目前最新的PHP版本是7.1.4,有兴趣的话可以看看这篇文章PHP7
新特性,改变变化。

其实PHP入门很容易,尤其是对于一个已经接触过程序编写的人来说,而对于没有接触过程序语言的菜鸟来说,学习用PHP做一个输出hello
world的网页也很轻松。

硬件

怎样才算是高性能的PHP应用?

性能和速度不是一对同义词。实现最佳性能通常需要在速度、准确性和可扩展性之间进行权衡。例如,在开发Web应用时,如果你优先考虑速度,你可能会编写一个将所有内容都载入内存的脚本,而如果从可扩展性出发,可能你就会编写以块为单位将数据载入内存的脚本。

基于phpLens的研究,下图展示了速度与可扩展性之间理论上的权衡关系。

澳门新浦京手机版 2

红线表示针对速度进行了优化的脚本,蓝线是可扩展性优先的脚本。当并发连接数低时,红线运行速度更快;
然而,随着并发连接数量的增加,红线变慢。当并发连接数上升时,蓝线也减慢;然而,下降并不那么剧烈,因此,在一定阈值后,速度优先的脚本会比可扩展性优先的脚本慢。然而,在现实当中,一些脚本可能随着运行环境的变化而表现出前后不同的性能差异。你需要仔细的观察用户的使用情况,以及应用的并发请求数量,来适时调整合适的优化策略。

然而要编写高效率的代码,并不是所有懂程序的人都可以编写出来的,这需要经过多年的研究积累和经验总结。

操作系统/软件库

PHP代码优化最佳实践

编写好的PHP代码是创建快速稳定Web应用的关键一步。从一开始就遵循一些最佳实践技巧将节省后期填坑的时间。

本文将给大家提炼一些PHP代码优化的实例,利用这些优化,PHP代码的运行能力将会大大提高,速度提升5倍以上有些情况下并不是不能出现。

SQL服务器(设置和查询)

1. 尽可能的使用PHP的内置方法

只要可以尽可能的使用PHP的内置方法,而不是自己编写相同功能的方法。花点时间去熟悉和学习PHP的内置方法,不但可以帮助你更快的编写代码,而且可以使你编写的代码更高效的运行。

1、echo 比 print 快

应用编程接口(API)

2. 使用Json替代xml

json_encode()和json_decode() 等PHP的内置方法,运行速度都非常快,所有应该优先使用Json。如果你无法避免使用xml,那么请务必使用正则表达式而不是DOM操作来进行解析。

echo和print是PHP程序中经常使用的指令,尤其是需要调试的时候。echo和print都能输出一段信息,但经测试发现,echo运行速度会比print快,因此在程序编写是应使用echo而非print。但是有时候也需要用到print,echo不能完全代替print。请看php
echo()和print()有什么区别。

应用程序

3. 使用缓存技术

Memcache特别适用于减少数据库负载,而像APC或OPcache这样的字节码缓存引擎在脚本编译时可节省执行时间。

2、连接符用逗号而不是句号

二、优化硬件

4. 减少不必要的计算

当一个变量会被多次使用时,一开始就计算好,肯定要比每次使用时都计算一遍要更高效。

php里逗号和句号都可以起到连接符的作用,关于如何优化输出,可以看这里如何优化php字符串echo输出。

如果你需要庞大的数据库表(>2G),你应该考虑使用64位的硬件结构,像Alpha、Sparc或即将推出的IA64。因为MySQL内部使用大量64位的整数,64位的CPU将提供更好的性能。

5. 使用isset()和empty()

与count()、strlen()和sizeof()函数相比,isset()和empty()对于检测一个变量是否为空等场景更加简单和高效。

此外,输出多个字符串时,用逗号代替句点来分隔字符串,速度更快。

对大数据库,优化的次序一般是RAM、快速硬盘、CPU能力。

6. 减少不必要的类

如果你不打算重复使用一个类或者方法,那么它就没什么存在的价值。而如果你必须要定义和使用一个类,则需要合理规划类中的方法,对于不是特别公用的方法,尽量将他们放到子类中去,因为调用子类中的方法,比调用父类方法速度更快。

3、在执行for循环之前确定最大循环数,不要每循环一次都计算最大值。

更多的内存通过将最常用的键码页面存放在内存中可以加速键码的更新。

7. 在生产环境关闭用作调试的相关代码及错误报告

开发时打开错误报告,可以让你避免很多潜藏的Bug,而一些调试代码也有助于你定位Bug,但是当代码部署到生产环境后,这些错误报告和调试代码会拖慢你的程序速度,而且将一些错误报告直接显示给用户,也具有相当的安全风险。因此,在生产环境请关闭它们。

这条准则同样适用于任何语言,这个是编程习惯,但这个习惯很不好,不管你使用什么语言。

如果不使用事务安全(transaction-safe)的表或有大表并且想避免长文件检查,一台UPS就能够在电源故障时让系统安全关闭。

8. 关闭数据库连接

当使用完毕后,注销变量和关闭数据库连接,可以释放珍贵的内存资源。

// 在每次循环中sizeof函数都要被调用

对于数据库存放在一个专用服务器的系统,应该考虑1G的以太网。延迟与吞吐量同样重要。

9. 使用聚合函数减少数据库查询

查询数据库时,使用聚合函数,可以减少检索数据库的频率,并且使程序运行的更快。

for ($i = 0; $i < sizeof($post_data); $i++)

三、优化磁盘

10. 使用强大的字符串操作函数

举个例子,str_replace()比preg_replace()要快,而strtr()函数则比str_replace()函数快四倍。

{

为系统、程序和临时文件配备一个专用磁盘,如果确是进行很多修改工作,将更新日志和事务日志放在专用磁盘上。

11. 尽量使用单引号

如果可能,尽量使用单引号替代双引号。程序运行时,会检查双引号中的变量,这会拖慢程序的性能。

do_澳门新浦京手机版,something();

低寻道时间对数据库磁盘非常重要。对与大表,你可以估计你将需要log(行数)/log(索引块长度/3*2/(键码长度

12. 尝试使用恒等运算符

由于“===”仅检查闭合范围,因此比使用“==”进行比较速度更快。

}

  • 数据指针长度))+1次寻到才能找到一行。对于有500000行的表,索引Mediun
    int类型的列,需要log(500000) / log(1024/3*2/(3 +
    2))+1=4次寻道。上述索引需要500000*7*3/2=5.2M的空间。实际上,大多数块将被缓存,所以大概只需要1-2次寻道。

PHP代码之外的性能瓶颈因素

优化代码当然能够提高PHP的性能。但是,还有一些代码之外的因素也会成为PHP的性能瓶颈。这就是为什么程序员需要了解代码部署的整个服务器环境,这有助于他们在编写代码时有一定的心理准备,并能够在性能出现问题时,快速识别和定位性能瓶颈。以下是你遇到性能瓶颈时需要检查的点。

// 您可以在循环起始部分对这个不变的量赋值

然而对于写入(如上),你将需要4次寻道请求来找到在哪里存放新键码,而且一般要2次寻道来更新索引并写入一行。

1. 网络带宽

如果网络带宽不够,其传输的总数据量将会受到严重影响,使其成为最明显的性能瓶颈。

for ($i = 0, $size = sizeof($post_data); $i < $size; $i++)

对于非常大的数据库,你的应用将受到磁盘寻道速度的限制,随着数据量的增加呈N
log N数据级递增。

2. CPU

如果只是传输一些纯静态的HTML,则不需要消耗很多CPU资源,但是PHP毕竟创建的是动态的应用程序,根据应用的需要,你可能至少需要一台具备多核处理器的服务器来提升PHP代码的运行效率。

{

将数据库和表分在不同的磁盘上。在MySQL中,你可以为此而使用符号链接。

3. 共享内存

缺少共享内存可能会影响进程间通信,从而影响程序性能。

do_something();

条列磁盘(RAID 0)将提高读和写的吞吐量。

4. 文件系统

随着时间推移,你的文件系统可能会出现大量磁盘碎片。如果内存足够,利用内存作为文件缓存可以加快磁盘的访问速度。

}

带镜像的条列(RAID
0+1)将更安全并提高读取的吞吐量。写入的吞吐量将有所降低。

5. 进程管理

检查服务器的进程,确保里面没有非必要的进程。移除哪些不需要的网络协议、病毒扫描软件、邮件服务以及硬件驱动。将PHP代码运行在多线程模式,也能提高程序的响应时间。

4、使用选择分支语句(译注:即switch case)好于使用多个if,else
if语句。

不要对临时文件或可以很容易地重建的数据所在的磁盘使用镜像或RAID(除了RAID
0)。

6. 相关的其它服务

如果你的应用程序还依赖于一些外部服务,那这些外部服务的性能瓶颈也有可能拖慢你的应用。虽然这种情况下你能做的事情不多,但你仍然可以通过你这一边的操作来减轻外部服务性能瓶颈对你的影响,例如切换到备用服务上等。

if else if
的使用非常普遍,在其他语言里也一样,这个写法好像更符合人的说话习惯,但是在程序里这样写并不太好,它在效率上比switch
case要低。所以,一旦程序里需要多个判断时,就应该用switch
case而不要再用if else if else if这样。

在Linux上,在引导时对磁盘使用命令hdparm -m16
-d1以启用同时读写多个扇区和DMA功能。这可以将响应时间提高5~50%。

更多PHP性能优化建议

5、数据库连接当使用完毕时应关掉

在Linux上,用async (默认)和noatime挂载磁盘(mount)。

1. 发挥OPCache的优势

由于默认情况下,PHP代码在执行时都会重新编译为可执行的中间代码OPCode,因此可以及时看到修改的代码所带来的变化,而不必频繁的重启PHP服务。不幸的是,如果每次在你的网站上运行时,都重新编译相同的代码会严重影响服务器的性能,这就是为什么opcode缓存或OPCache 非常有用。

OPCache是一个将编译好的代码保存到内存中的扩展。因此,下一次代码执行时,PHP将检查时间戳和文件大小,以确定源文件是否已更改。如果没有,则直接运行缓存的代码。

下图显示了运行无缓存的PHP应用程序,OPcache和eAccelerator(另一个PHP缓存工具)三者的执行时间和内存使用情况的差异。

澳门新浦京手机版 3

图片来源: Prestashop

在操作数据库时,很多程序员往往忘记关掉数据库连接,或许他们没有这个习惯。数据库连接是需要消耗内存为代价的,连接数越多内存消耗就越多,所以在实际应用中都必须及时关闭不需要用到的连接,以释放内存,缓解服务器压力。

对于某些特定应用,可以对某些特定表使用内存磁盘,但通常不需要。

2. 识别数据库响应延迟

如上所述,性能问题并不总是由代码引起的。大多数瓶颈都出现在应用程序必须访问资源的时候。由于PHP应用程序的数据访问层可能占用最高90%的执行时间,因此你应该采取的第一步是查看代码中访问数据库的所有实例。

确保打开SQL的慢日志,以帮助你识别和处理慢SQL,然后评估这些查询的执行效率。如果你发现查询过多,或者在单次执行过程中发现相同的查询被多次进行,你可以通过减少数据库访问时间进行调整,从而提高应用程序的性能。

6、错误消息代价昂贵

四、优化操作系统

3. 清理文件系统

清理文件系统,并确保没有使用文件系统来存储Session。最重要的是,请注意file_exists(),filesize()或filetime()等触发文件统计信息的代码。将任何这些功能置于循环中可能会导致性能问题。

错误消息一般用于调试,它的执行效率其实是很低的,速度上会比直接运行慢很多。所以,在程序不需要抓取错误消息时,就不要用。

不要交换区。如果内存不足,增加更多的内存或配置你的系统使用较少内存。

4. 监控外部API接口

大部分对外部系统有依赖关系的应用都会调用远程API。虽然这些远程API接口你无法直接控制,但你仍可以采取一些措施来减轻源自远程API的性能问题。例如,你可以缓存API输出的数据,或者可以在后台调用这些API。为API请求设置合理的超时时间,并且如果可能的话,随时做好API没有响应的情况下的显示输出。

7、局部变量要合理使用

不要使用NFS磁盘(会有NFS锁定的问题)。

5. 使用工具评估检测你的PHP代码

使用OPcache和监控外部API接口应该足以使大多数应用程序运行顺利;但是,如果你发现系统负载不断增加,那么可能需要使用工具来对你的PHP代码进行检测评估。完整的PHP代码检测评估虽然可能很耗时,但它可以为你提供有关应用程序性能的深入信息。幸运的是,有几个开源程序可以用于分析你的PHP代码,如Xdebug。

尽量不要在for循环中使用函数,比如for ($x=0; $x
prop++)要比递增一个局部变量慢3倍。

增加系统和MySQL服务器的打开文件数量。(在safe_mysqld脚本中加入ulimit -n
#)。

监控PHP性能的重要性

如果你没有做好准备,你的Web应用可能前一分钟还在正常运行,但是下一分钟,一波突然激增的流量就会导致你的应用程序崩溃。
当然,优化和重构总是需要时间、精力和资金,而且投入是否值得的也很难说。因此,做出明智决策的最佳方式是不断收集数据

PHP性能监控软件可以帮助你立即测量所做的任何更改的影响。当然,知道要监测什么同样重要。速度和内存使用被认为是性能的最佳指标,因为它们影响到页面加载时间,这对Web应用程序至关重要。

虽然数据收集很重要,但是当你不需要监控系统时,你应该关闭监控系统,因为大量日志同样也会对性能造成影响。当然,这样的日志可以提供有关如何提高性能的有用信息,因此你应该在高峰期间定期监控。

递增一个未预定义的局部变量要比递增一个预定义的局部变量慢9至10倍。

增加系统的进程和线程数量。

未来的PHP性能

PHP仍在不断进化中,在目前正在开发的PHP
8版本中,最新的功能是即时编译或JIT,它将可以为我们创建更快的Web应用。随着技术的不断进步,用户的期望也随之增加。因此,开发人员必须始终关注未来的变化。

在构建Web应用程序时,请记住,今年的工作可能在明年不起作用。你可能需要进行调整才能持续保持优秀的PHP性能。在开发过程中,应该持续重点关注如何构建适用于高并发场景的Web应用和网站,保证它们的高可用性。

仅定义一个局部变量而没在函数中调用它,同样会减慢速度(其程度相当于递增一个局部变量)。PHP大概会检查看是否存在全局变量。

如果你有相对较少的大表,告诉文件系统不要将文件打碎在不同的磁道上(Solaris)。

8、用单引号代替双引号来包含字符串

使用支持大文件的文件系统(Solaris)。

实践证明,用单引号代替双引号来包含字符串,这样做会更快一些。

选择使用哪种文件系统。在Linux上的Reiserfs对于打开、读写都非常快。文件检查只需几秒种。

因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会。当然,只有当你不需要在字符串中包含变量时才可以这么做。更多分析请看实例分析php单引号和双引号的区别。

五、选择应用编程接口

9、mod_zip你用了吗

PERL

mod_zip可作为Apache模块,用来即时压缩你的数据,并可让数据传输量降低80%。

可在不同的操作系统和数据库之间移植。

10、缓存的使用

适宜快速原型。

除非脚本可以缓存,否则每次调用时都会重新编译一次。引入一套PHP缓存机制通常可以提升25%至100%的性能,以免除编译开销。

应该使用DBI/DBD接口。

尽量做缓存,可使用memcached。memcached是一款高性能的内存对象缓存系统,可用来加速动态Web应用程序,减轻数据库负载。对运算码
(OP code)的缓存很有用,使得脚本不必为每个请求做重新编译。

PHP

11、网页用html而非php

比PERL易学。

毫无疑问,html静态页面的访问速度是最快的,现在的CMS,都是可以在后台生成全站HTML静态页面的,这不仅可以提高用户访问网页的速度,而对于搜索引擎的收录和排名也是非常有利的。

使用比PERL少的资源。

以上几点是本文提炼出来的PHP优化方法,当然,优化PHP绝非仅此一点,所谓学无止境,许许多多的优化方法和技巧,需要我们在实践中不断总结和运用。

通过升级到PHP4可以获得更快的速度。

C

MySQL的原生接口。

较快并赋予更多的控制。

低层,所以必须付出更多。

C++

较高层次,给你更多的时间来编写应用。

仍在开发中

ODBC

运行在Windows和Unix上。

几乎可在不同的SQL服务器间移植。

较慢。MyODBC只是简单的直通驱动程序,比用原生接口慢19%。

有很多方法做同样的事。很难像很多ODBC驱动程序那样运行,在不同的领域还有不同的错误。

问题成堆。Microsoft偶尔还会改变接口。

不明朗的未来。(Microsoft更推崇OLE而非ODBC)

ODBC

运行在Windows和Unix上。

几乎可在不同的SQL服务器间移植。

较慢。MyODBC只是简单的直通驱动程序,比用原生接口慢19%。

有很多方法做同样的事。很难像很多ODBC驱动程序那样运行,在不同的领域还有不同的错误。

问题成堆。Microsoft偶尔还会改变接口。

不明朗的未来。(Microsoft更推崇OLE而非ODBC)

JDBC

理论上可在不同的操作系统何时据库间移植。

可以运行在web客户端。

Python和其他

可能不错,可我们不用它们。

六、优化应用

应该集中精力解决问题。

在编写应用时,应该决定什么是最重要的:

速度

操作系统间的可移植性

SQL服务器间的可移植性

使用持续的连接。.

缓存应用中的数据以减少SQL服务器的负载。

不要查询应用中不需要的列。

不要使用SELECT * FROM table_name…

测试应用的所有部分,但将大部分精力放在在可能最坏的合理的负载下的测试整体应用。通过以一种模块化的方式进行,你应该能用一个快速“哑模块”替代找到的瓶颈,然后很容易地标出下一个瓶颈。

如果在一个批处理中进行大量修改,使用LOCK
TABLES。例如将多个UPDATES或DELETES集中在一起。

七、应该使用可移植的应用

Perl DBI/DBD

ODBC

JDBC

Python(或其他有普遍SQL接口的语言)

你应该只使用存在于所有目的SQL服务器中或可以很容易地用其他构造模拟的SQL构造。[url]www.mysql.com上的Crash-me页可以帮助你。[/url]

为操作系统/SQL服务器编写包装程序来提供缺少的功能。

八、如果你需要更快的速度,你应该:

找出瓶颈(CPU、磁盘、内存、SQL服务器、操作系统、API或应用)并集中全力解决。

使用给予你更快速度/灵活性的扩展。

逐渐了解SQL服务器以便能为你的问题使用可能最快的SQL构造并避免瓶颈。

优化表布局和查询。

使用复制以获得更快的选择(select)速度。

如果你有一个慢速的网络连接数据库,使用压缩客户/服务器协议。

不要害怕时应用的第一个版本不能完美地移植,在你解决问题时,你总是可以在以后优化它。

 

九、优化MySQL

挑选编译器和编译选项。

位你的系统寻找最好的启动选项。

通读MySQL参考手册并阅读Paul DuBios的《MySQL》一书。(已有中文版-译注)

多用EXPLAIN SELECT、SHOW VARIABLES、SHOW STATUS和SHOW PROCESSLIST。

了解查询优化器的工作原理。

优化表的格式。

维护你的表(myisamchk、CHECK TABLE、 OPTIMIZE TABLE)

使用MySQL的扩展功能以让一切快速完成。

如果你注意到了你将在很多场合需要某些函数,编写MySQL UDF函数。

不要使用表级或列级的GRANT,除非你确实需要。

购买MySQL技术支持以帮助你解决问题:)

 

十、编译和安装MySQL

通过位你的系统挑选可能最好的编译器,你通常可以获得10-30%的性能提高。

在Linux/Intel平台上,用pgcc(gcc的奔腾芯片优化版)编译MySQL。然而,二进制代码将只能运行在Intel奔腾CPU上。

对于一种特定的平台,使用MySQL参考手册上推荐的优化选项。

一般地,对特定CPU的原生编译器(如Sparc的Sun
Workshop)应该比gcc提供更好的性能,但不总是这样。

用你将使用的字符集编译MySQL。

静态编译生成mysqld的执行文件(用–with-mysqld-ldflags=all-static)并用strip
sql/mysqld整理最终的执行文件。

注意,既然MySQL不使用C++扩展,不带扩展支持编译MySQL将赢得巨大的性能提高。

如果操作系统支持原生线程,使用原生线程(而不用mit-pthreads)。

用MySQL基准测试来测试最终的二进制代码。

 

十一、维护

如果可能,偶尔运行一下OPTIMIZE table,这对大量更新的变长行非常重要。

偶尔用myisamchk -a更新一下表中的键码分布统计。记住在做之前关掉MySQL。

如果有碎片文件,可能值得将所有文件复制到另一个磁盘上,清除原来的磁盘并拷回文件。

如果遇到问题,用myisamchk或CHECK table检查表。

用mysqladmin -i10 precesslist extended-status监控MySQL的状态。

用MySQL GUI客户程序,你可以在不同的窗口内监控进程列表和状态。

使用mysqladmin debug获得有关锁定和性能的信息。

 

十二、优化SQL

扬SQL之长,其它事情交由应用去做。使用SQL服务器来做:

找出基于WHERE子句的行。

JOIN表

GROUP BY

ORDER BY

DISTINCT

不要使用SQL来做:

检验数据(如日期)

成为一只计算器

技巧:

明智地使用键码。

键码适合搜索,但不适合索引列的插入/更新。

保持数据为数据库第三范式,但不要担心冗余信息或这如果你需要更快的速度,创建总结表。

在大表上不做GROUP BY,相反创建大表的总结表并查询它。

UPDATE table set count=count+1 where key_column=constant非常快。

对于大表,或许最好偶尔生成总结表而不是一直保持总结表。

充分利用INSERT的默认值。

 

十三、不同SQL服务器的速度差别(以秒计)

 

通过键码读取2000000行: NT Linux

mysql 367 249

mysql_odbc 464  

硬件 操作系统/软件库
SQL服务器(设置和查询) 应用编程接口(API) 应用程序 二、优化硬件
如果你需要庞大的…

发表评论

电子邮件地址不会被公开。 必填项已用*标注