PHP性能优化

语言级性能优化 =》 PHP 周边问题性能优化( webservice 、mysql 缓存) =》 PHP 语言自身分析、优化(底层C的优化)

ab -n(请求数) -c (并发数)

1
ab -n 100 -c 10

PHP 语言级的性能优化

1.少写代码,多用 PHP 内置的函数,变量,常量。

自写代码冗余较多,性能低。(PHP 代码越长,执行时间越长),

PHP 需要词法分析,语法分析编译为底层语言,每请求一次都会处理一遍,开销大。

$arr1 = $arr2 = range(1000,2000);
取代 for(i = 0 ; i<rand(1000,2000);i++;)
{

}

shuffle()

array_merge()

  1. PHP (有几千个内置函数);

    PHP内置函数之间依然存在快慢差异,多去了解PHP 内置函数的时间复杂度。

    iset($arr[$i]) //50ms

    array_key_exists($i,$arr) //85ms

  2. PHP魔法函数 (尽量规避使用PHP魔法函数,性能不佳)

    为什么性能够低?

    为了给PHP 程序员省事,PHP 语言底层为你做了很多。
    
     所以尽可能的避免使用PHP的魔法函数;

    举例:

    __get 性能测试
    
    time php test_magic.php
  1. 产生额外开销的错误抑制符 @

    PHP提供的错误抑制符只是为了方便 “懒人”(图方便的)

    @的实际逻辑:

    在@那行代码语句前后增加opcode,(这些opcode就是在报错之前加一个 error_ poring的报错级别的设置设置成忽略, 在@之后又加了一些opcode 将报错级别恢复,)从而忽略报错;

vld - PHP Opcode PHP的扩展来查看opcode

尽量不要使用 @ 错误抑制符;  尽量用 try  throw这种错误控制;
  1. 合理使用内存

    PHP 有内存回收机制保底,但也请小心使用内存;

    处理数组,取到大数组。使用很多额外的内存。

    好的建议:

    利用unset() 及时释放不适用的内存(注:unset()出现注销不了的情况)
  2. 尽量少使用正则表达式

    使用起来简单,性能比较低;当我们的正则表达式匹配的项越多,回溯的开销也就越来越大。 优化正则表达式,也是PHP 项目中常见的优化项目。(需要一定的技术水平,没有金刚钻别揽瓷器活)

    好的建议

    利用字符串处理函数,实现相同逻辑;
  3. 避免在循环内做运算

    循环判断式中的计算。将会被重复计算。

1
2
3
4
5
6
7
8
9
10
11
12
<?php
$str = "hello world";

for($i = 0 ; $i < str_len($str); $i ++){
// do sometihing
}

$str_len = str_len($str);

for($i = 0 ; $i < $str_len; $i ++){
// do sometihing
}

8. 减少计算密集型业务 (大批量日志分析,大批量数据处理等)

PHP 语言特性决定了PHP 不适合 大数据量运算,
PHP底层是C实现的,它的所有处理都要转换成C语言,处理运算额外的开销相对于C 要大很多。PHP的变量寄存,数据储存运算都需要让C来实现。不擅长计算。

PHP适合衔接webserver与后端服务,UI呈现。

8.1 衔接webserver

webserver来的请求交给PHP,PHP做一些参数校验、做一些验证、初始化处理,
将请求转发给后端,并且等待后端响应 【可能是 DB,缓存。 可能是其他业务,后端响应之后,PHP又作为纽带返回给 webserver】

8.2 后端服务 UI 呈现

适合配合一些模版引擎做UI呈现。 适合字符串以及文本处理

有一些并发,多线程的拓展(swoole) 但还是不适合做密集型业务处理; 有一些密集型计算是由PHP来做的话这快就是性能瓶颈了。

9. 务必使用带引号字符串做键值

PHP 会将没有引号的键值当做常量,(会去查找常量集)产生查找常量的开销。

1
2
3
4
5
6
7
8
9
10
11
12
<?php
define("key", "imooc");
$arr = [
"key" => "hello world",
"imooc" => 'http://www.imooc.com'
];
echo $arr["key"]; // 输出 hello world
echo $arr[key]; // 输出 http://www.imooc.com

注释掉 define 继续输出

echo $arr[key]; // 首先会有一个 notice的报错, 然后输出 hello world. 多了一步 查找常量的开销。 有引号的会直接去数组内部查找。

2. PHP 周边问题的性能优化

2.1 PHP 周边都有什么?

linux运行环境、文件存储(磁盘的读写速度)、数据库(基于文件系统的软件)、缓存(软硬结合的缓存机制,硬件的内存,软件的readis/memercache缓存)、 网络(带宽大小,介质)

BD.php 连接数据库如果要800ms 那么其中 600ms是在DB内部,网络 60100ms,PHP 脚本 应该只有2030ms;
优化的时候看 是 脚本 语法写的不太好, 还是周边服务产生的瓶颈;

image

优化的思想找出问题的重点,核心是什么。抓大头去下手。

2.2 减少文件类的操作

常见PHP场景( 读写磁盘、读写数据库、读写内存、读写网络数据 )的开销次序:

读写内存 << 读写数据库  < 磁盘  < 读写网络

读写内存是PHP直接通过底层的PHP引擎操作机器的内存数据,这个操作是与本地磁盘没有交接的;

数据库是文件系统,PHP 操作数据库就是操作磁盘;

数据库一般都会使用内存做缓存,将热数据(要写如数据库的数据先缓存在内存,异步的写入数据库,insert操作其实是先将这条指令写入内存中,写成功就告诉PHP写OK了,再将 insert语句操作本地数据库。)

读写网络, 是基于socket,socket是使用的本地的文件句柄。 读网络数据其实也是一个磁盘操作。(为什么要大一些,有一个隐性因子就是网络延迟);因此要尽量减少读写网络的情况;

后面三个都是基于磁盘,基于linux的文件系统;

2.3 减少PHP发起的网络请求

1.1. 对方接口的不稳定性;
1.2. 数据格式类型不对称;

2.1 网络稳定性;

方法1:设置超时时间:

(连接超时 200ms;读超时 800ms;写超时(get/post)500ms)

方法二:串行请求并行化:

推荐 swoole