原文转自:https://learnku.com/docs/php-design-patterns/2018/Pool/1491
对象池模式是一种提前准备了一组已经初始化了的对象『池』而不是按需创建或者销毁的创建型设计模式。对象池的客户端会向对象池中请求一个对象,然后使用这个返回的对象执行相关操作。当客户端使用完毕,它将把这个特定类型的工厂对象返回给对象池,而不是销毁掉这个对象。
在初始化实例成本高,实例化率高,可用实例不足的情况下,对象池可以极大地提升性能。在创建对象(尤其是通过网络)时间花销不确定的情况下,通过对象池在可期时间内就可以获得所需的对象。
无论如何,对象池模式在需要耗时创建对象方面,例如创建数据库连接,套接字连接,线程和大型图形对象(比方字体或位图等),使用起来都是大有裨益的。在某些情况下,简单的对象池(无外部资源,只占内存)可能效率不高,甚至会有损性能。在swoole的框架中一般在控制器中会使用对象池模式。
在swoole框架基本上都使用这个模式。
例如easyswoole文档中的说明
- 用户A请求
/Index
,经过url解析以及路由转发,定位到了App\HttpController\Index.php
- 控制器由于是第一次请求,
new App\HttpController\Index.php
,并将该对象存入到对象池中。 - 对象池出列,获取该对象,并进行调用index方法进行处理请求
- 处理完毕,将对象的属性重置为默认值,对象回收对象池
- 用户B请求
/Index
,经过url解析以及路由转发,定位到了App\HttpController\Index.php
- 控制器由于是二次请求,对象池直接获取到第一次的对象,不需要new,直接调用 index方法进行处理。
对象池模式
实现了不同请求复用同一个对象,降低了创建/销毁对象的开销
只有第一次请求 创建对象才会调用构造函数,在第二次请求获取对象时将不会再次调用
对象池模式
不会重置静态属性和private私有属性,这2种属性将会复用
对象池模式
是针对单一进程的,多个work进程的对象池不共享.
简单的对象池demo
StringReverseWorker.php
namespace App\Pool;
class StringReverseWorker
{
/**
* @var \DateTime
*/
private $createdAt;
public function __construct()
{
$this->createdAt = new \DateTime();
}
public function run(string $text, array $callback)
{
echo strrev($text);
//把$this做为参数返回到调用此方法的对象里的回调方法
call_user_func($callback, $this);
}
}
WorkerPool.php
namespace App\Pool;
class WorkerPool implements \Countable
{
/**
* @var StringReverseWorker[]
*/
private $occupiedWorkers = [];
/**
* @var StringReverseWorker[]
*/
private $freeWorkers = [];
public function get(): StringReverseWorker
{
if (count($this->freeWorkers) == 0) {
$worker = new StringReverseWorker();
} else {
$worker = array_pop($this->freeWorkers);
}
$this->occupiedWorkers[spl_object_hash($worker)] = $worker;
return $worker;
}
public function dispose(StringReverseWorker $worker)
{
$key = spl_object_hash($worker);
if (isset($this->occupiedWorkers[$key])) {
unset($this->occupiedWorkers[$key]);
$this->freeWorkers[$key] = $worker;
}
}
public function callback($responseObj)
{
var_dump($responseObj);
echo "从调用类返回过来。";
}
public function test()
{
$worker =$this->get();
//设置回调函数在run方法中完成逻辑并且返回到自己
$worker->run('123<br/>',array($this,'callback'));
}
/**
* 返回占用的对象数和空闲的对象数
* @return int
*/
public function count(): int
{
return count($this->occupiedWorkers) + count($this->freeWorkers);
}
}
调用代码
require "Loader.php";
Loader::init();
use App\Pool\WorkerPool;
$pool = new WorkerPool();
$pool->test();
echo"<br/>";
echo Loader::getLoadFileNum();