前言
对象池(也称为资源池)被用来管理对象缓存。对象池是一组已经初始化过且可以直接使用的对象集合,用户在使用对象时可以从对象池中获取对象,对其进行操作处理,并在不需要时归还给对象池而非销毁它。
若对象初始化、实例化的代价高,且需要经常实例化,但每次实例化的数量较少的情况下,使用对象池可以获得显著的性能提升。常见的使用对象池模式的技术包括线程池、数据库连接池、任务队列池、图片资源对象池等。
当然,如果要实例化的对象较小,不需要多少资源开销,就没有必要使用对象池模式了,这非但不会提升性能,反而浪费内存空间,甚至降低性能。
对象池模式
<?php
/**
* 数据库操作
*/
class Mysql
{
/**
* 查询
*
* @access public
*/
public function select ()
{
echo '这是一个查询<br>';
}
}
/**
* 定义对象池
*/
class ObjectPool
{
/**
* 空闲连接池
*
* @var array
*/
private $freePools = [];
/**
* 工作连接池
*
* @var array
*/
private $workPools = [];
/**
* 最大连接池数量
*
* @var int
*/
private $maxPoolNum = 3;
/**
* 连接池现有数量
*
* @var int
*/
private $nowPoolNum = 0;
/**
* 从池子获取对象
*
* @access public
* @param int $num 连接编号,用来学习时,方便观察
* @return Mysql|bool
*/
public function getPool ($num = 0)
{
if ($this->nowPoolNum === 0 || ($this->nowPoolNum < $this->maxPoolNum && count($this->freePools) === 0)) {
// 池子没有连接,或者连接池未满,新建连接
$worker = new Mysql;
// 将连接追加进工作连接池中
$this->workPools[spl_object_hash($worker)] = $worker;
// 已有连接数量+1
$this->nowPoolNum++;
} else if (count($this->freePools) > 0) {
// 从空闲连接池中获取一个连接
$worker = array_pop($this->freePools);
// 将连接追加进工作连接池中
$this->workPools[spl_object_hash($worker)] = $worker;
} else {
echo '!!!!!没有空闲的连接,连接 ' . $num . ' 获取失败,请稍后再试!!!!!<br>';
return false;
}
echo '获取连接 ' . $num . ' 成功<br>';
return $worker;
}
/**
* 释放工作中的数组
*
* @access public
* @param string $key 数组键值
* @return bool
*/
public function releasePool ($worker, $num)
{
// 加密对象,获取key值
$key = spl_object_hash($worker);
// 判断是否存在
if (isset($this->workPools[$key])) {
// 释放数据
unset($this->workPools[$key]);
// 将对象放回空闲连接池
$this->freePools[spl_object_hash($worker)] = $worker;
return true;
}
return false;
}
}
/**
* 定义测试类
*/
class TestPool
{
/**
* 使用数据库操作
*
* @access public
* @return void
*/
public function test ()
{
// 实例化对象池
$objectPool = new ObjectPool;
// 获取连接
$worker1 = $objectPool->getPool(1);
$worker2 = $objectPool->getPool(2);
$worker3 = $objectPool->getPool(3);
$worker4 = $objectPool->getPool(4);
// 释放连接
if ($objectPool->releasePool($worker3, 3)) {
echo '释放连接 3 成功<br>';
} else {
echo '释放连接 3 失败<br>';
}
// 重新获取连接4
$worker4 = $objectPool->getPool(4);
}
}
$test = new TestPool;
$test->test();
我们来看看测试结果:
从这里我们可以看出,前面三个成功获取连接,第四个由于没有空闲的连接,所以获取失败,后面释放了连接3之后,连接4又可以重新获取了。