关于php对象池
对象复用
对象复用以及不复用的效率
那么这个时候可能会有人问?new一个对象,多大事啊!给它new不就得了!针对这个问题,我们可以来测试下new一个对象的消耗有多大
新建一个测试脚本:
<?php
class Test
{
protected $a;
public function __construct($a)
{
$this->a = $a;
}
public function setA($a)
{
$this->a = $a;
}
public function getA()
{
return $this->a;
}
}
$startTime = microtimeFloat();
for ($i = 0; $i < 10000; $i++) {
$test = new Test($i);
$test->getA();
}
echo "对象不复用耗时" . (microtimeFloat() - $startTime) . '秒' . PHP_EOL;
$startTime = microtimeFloat();
$test = new Test(0);
for ($i = 0; $i < 10000; $i++) {
$test->setA($i);
$test->getA();
}
echo "对象复用耗时" . (microtimeFloat() - $startTime) . '秒' . PHP_EOL;
function microtimeFloat()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
测试结果
/usr/local/php-7.2.2/bin/php /home/tioncico/PhpstormProjects/test/test.php
对象不复用0.0012578964233398秒
对象复用 0.00068378448486328秒
可看出,在对象复用情况下,效率比不复用情况快了一倍,可能有人会说:缺这么性能算什么?根本看不出啊!
这是因为测试文件的类是最简单的类,如果是复杂点的,例如继承,多重继承构造函数,析构函数,以及triat等等复杂对象,花费的cpu可就不止这些了
为什么复用对象会比不复用快?
这个需要从2方面进行讲解
php实例化对象步骤
如果讲php实例化的底层的话,大家可能听不懂,我也不懂底层,所以本人用通俗的方法讲解下php实例化对象需要做的事情(步骤前后顺序可能有错)
1:实例化对象,检查对象属性,方法,结构等
2:属性初始化
3:对象父类属性初始化
4:构造函数初始化
可以看出,new 一个对象,所做的事跟对象的复杂度有关,比如类继承,类接口实现,检查对象继承接口等是否有错,初始化属性,调用构造函数等等
php 垃圾回收,同样,在回收一个对象时,需要销毁对象的所有属性,父类属性等等,以及调用析构函数等等
如果对象复用,这些操作将都不需要,我们只需要执行一次,即可复用
注:步骤等本人并没有详细了解,只根据本人经验进行模糊以及通俗解释
对象池
在上面的说明中,我们已经知道了对象复用的好处,那么如果我有2个请求同时进来呢?3个?10个?(多请求单进程处理需要php实现异步网络服务器,或者swoole协程网络服务器)
很明显,如果是多个请求同时处理,一个对象是不够用的.
那我们能不能先new 10个,或者100个,1000个,然后每次请求进来就分一个,标记为正在使用,其他请求不能再用这个,请求结束后标记为未使用,等待请求使用?
这个操作,就是对象池。
顾名思义,对象池是一个池子,每次我们需要对象时从里面拿一个,用完再放回去,这样又实现了对象复用,又实现了能同时处理多个请求
对象池的意义
上面我们可能发现了,对象池如果对象太少,比如只有10个,那10个都被人用了,岂不是第11个人没得用了?
答案是对的
那为什么不直接设置10000个,想多少人用就多少人用?
理论上是这样的,但是对象池的意义,就是限制并发的大小,防止服务器负载太高而进行宕机。
例如:
假设没有对象池,也没有对象复用,在传统web模式下,假设进程也有100,10000个,一个请求进来需要消耗1%的cpu
当100个请求进来的时候,cpu已经为100%,勉强全部能运行
而出现101个请求之后,某个请求会因为cpu资源不够,处理将会变慢,直到其他请求处理好一个,腾出1%去处理新的请求
如果当出现200个请求,cpu由于分时调度(尽量使得所有请求处理的时间尽量平均),会使得所有请求平均响应时间慢一倍(如果有一个进程正常响应,那么就说明有几个请求需要慢2倍甚至更多)再到后面,将会出现只能响应少数请求,其他请求全部超时无法正常响应的宕机情况
上面的cpu资源争夺是其一,其二是消耗内存,如果同时处理太多进程,还有可能造成服务器内存不够。
对象池的意义就在于此:
设定合理的对象池数量,当超出对象池数量时,让请求等待或者直接提示系统繁忙,保证其他请求进行正常响应,保证服务器的运行正常
例如设置了100个对象 第101个请求进来时,使其等待3秒,3秒内如果有对象回收,则直接给101个请求使用,否则3秒后告诉该请求服务器繁忙,请稍后再试,避免出现服务器调度混乱,导致宕机
php什么时候会用到对象池
由于对象池的特性,它只出现在单进程处理多个请求情况而出现(例如java的多线程同时处理),而php中大部分情况是没有的,目前只有在swoole协程中使用较多,或者在php异步网络服务器中使用