Skip to content

Commit

Permalink
pool 优化实现,实现免注册和通用对象池
Browse files Browse the repository at this point in the history
  • Loading branch information
kiss291323003 committed Jan 6, 2019
1 parent a17fab1 commit ce362d1
Show file tree
Hide file tree
Showing 7 changed files with 252 additions and 29 deletions.
119 changes: 118 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,118 @@
# abstractInterface
# PoolInterface

```
use EasySwoole\Component\Pool\PoolManager;
use EasySwoole\Component\Pool\TraitObjectInvoker;
use EasySwoole\Utility\Random;
use EasySwoole\Component\Pool\AbstractPoolObject;
use EasySwoole\Component\Pool\PoolObjectInterface;
use EasySwoole\Component\Pool\AbstractPool;
class test
{
public $id;
function __construct()
{
$this->id = Random::character(8);
}
function fuck(){
var_dump('this is fuck at class:'.static::class.'@id:'.$this->id);
}
}
class test2 extends test implements PoolObjectInterface
{
function objectRestore()
{
var_dump('this is objectRestore at class:'.static::class.'@id:'.$this->id);
}
function gc()
{
// TODO: Implement gc() method.
}
function beforeUse(): bool
{
// TODO: Implement beforeUse() method.
return true;
}
}
class testPool extends AbstractPool
{
protected function createObject()
{
// TODO: Implement createObject() method.
return new test();
}
}
class testPool2 extends AbstractPool
{
protected function createObject()
{
// TODO: Implement createObject() method.
return new test2();
}
}
class test3 extends test
{
use TraitObjectInvoker;
}
class test4 extends AbstractPoolObject
{
function finalFuck()
{
var_dump('final fuck');
}
function objectRestore()
{
var_dump('final objectRestore');
}
}
//cli下关闭pool的自动定时检查
PoolManager::getInstance()->getDefaultConfig()->setIntervalCheckTime(0);
go(function (){
go(function (){
$object = PoolManager::getInstance()->getPool(test::class)->getObj();
$object->fuck();
PoolManager::getInstance()->getPool(test::class)->recycleObj($object);
});
go(function (){
testPool::invoke(function (test $test){
$test->fuck();
});
});
go(function (){
testPool2::invoke(function (test2 $test){
$test->fuck();
});
});
go(function (){
test3::invoke(function (test3 $test3){
$test3->fuck();
});
});
go(function (){
$object = PoolManager::getInstance()->getPool(test4::class)->getObj();
$object->finalFuck();
PoolManager::getInstance()->getPool(test4::class)->recycleObj($object);
});
});
```
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"require": {
"php": ">=7.1.0",
"ext-swoole":"^4.0",
"easyswoole/swoole-ide-helper": "^1.2"
"easyswoole/swoole-ide-helper": "^1.2",
"easyswoole/utility": "^1.0"
},
"autoload": {
"psr-4": {
Expand Down
81 changes: 56 additions & 25 deletions src/Pool/AbstractPool.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@
use EasySwoole\Component\Pool\Exception\PoolEmpty;
use EasySwoole\Component\Pool\Exception\PoolNumError;
use EasySwoole\Component\Pool\Exception\PoolUnRegister;
use EasySwoole\Utility\Random;
use Swoole\Coroutine\Channel;

abstract class AbstractPool
{
private $createdNum = 0;
private $chan;
private $inuse = 0;
private $poolChannel;
private $objHash = [];
private $conf;
/*
Expand All @@ -32,7 +34,7 @@ public function __construct(PoolConf $conf)
throw new PoolNumError("pool max num is small than min num for {$class} error");
}
$this->conf = $conf;
$this->chan = new Channel($conf->getMaxObjectNum() + 1);
$this->poolChannel = new Channel($conf->getMaxObjectNum() + 1);
if($conf->getIntervalCheckTime() > 0){
swoole_timer_tick($conf->getIntervalCheckTime(),[$this,'intervalCheck']);
}
Expand All @@ -47,55 +49,68 @@ public function recycleObj($obj):bool
if($obj instanceof PoolObjectInterface){
$obj->objectRestore();
}
return $this->putObject($obj);
}else{
return false;
$ret = $this->putObject($obj);
if($ret){
$this->inuse--;
}
return true;
}
return false;
}

public function getObj(float $timeout = null,int $tryTimes = 3)
public function getObj(float $timeout = null,int $beforeUseTryTimes = 3)
{
if($timeout === null){
$timeout = $this->conf->getGetObjectTimeout();
}
if($tryTimes <= 0){
if($beforeUseTryTimes <= 0){
return null;
}
//懒惰创建模式
$obj = null;
if($this->chan->isEmpty()){
if($this->poolChannel->isEmpty()){
//如果还没有达到最大连接数,则尝试进行创建
if($this->createdNum < $this->conf->getMaxObjectNum()){
$this->createdNum++;
/*
* 创建对象的时候,请加try,尽量不要抛出异常
*/
$obj = $this->createObject();
if(!$this->putObject($obj)){
$this->createdNum--;
$hash = Random::character(16);
if(is_object($obj)){
//标记手动标记一个id spl_hash 存在坑
$obj->__objectHash = $hash;
//标记为false,才可以允许put回去队列
$this->objHash[$hash] = false;
if(!$this->putObject($obj)){
$this->createdNum--;
unset($this->objHash[$hash]);
}
}
//同样进入调度等待,理论上此处可以马上pop出来
$obj = $this->chan->pop($timeout);
$obj = $this->poolChannel->pop($timeout);
}else{
$obj = $this->chan->pop($timeout);
$obj = $this->poolChannel->pop($timeout);
}
}else{
$obj = $this->chan->pop($timeout);
$obj = $this->poolChannel->pop($timeout);
}
//对对象进行标记处理
if(is_object($obj)){
$key = spl_object_hash($obj);
//上一步已经put object了,put object中设置了__objectHash
$key = $obj->__objectHash;
//标记这个对象已经出队列了
$this->objHash[$key] = false;
if($obj instanceof PoolObjectInterface){
//请加try,尽量不要抛出异常
$status = $obj->beforeUse();
if($status == false){
if($status === false){
$this->unsetObj($obj);
//重新进入对象获取
return $this->getObj($timeout,$tryTimes - 1);
return $this->getObj($timeout,$beforeUseTryTimes - 1);
}
}
$this->inuse++;
return $obj;
}else{
return null;
Expand All @@ -108,15 +123,18 @@ public function getObj(float $timeout = null,int $tryTimes = 3)
public function unsetObj($obj):bool
{
if(is_object($obj)){
$key = spl_object_hash($obj);
if(!isset($obj->__objectHash)){
return false;
}
$key = $obj->__objectHash;
if(isset($this->objHash[$key])){
unset($this->objHash[$key]);
$this->createdNum--;
if($obj instanceof PoolObjectInterface){
$obj->objectRestore();
$obj->gc();
}
unset($obj);
$this->createdNum--;
return true;
}else{
return false;
Expand All @@ -133,8 +151,8 @@ public function gcObject(int $idleTime)
{
$list = [];
while (true){
if(!$this->chan->isEmpty()){
$obj = $this->chan->pop(0.001);
if(!$this->poolChannel->isEmpty()){
$obj = $this->poolChannel->pop(0.001);
if(is_object($obj)){
if(time() - $obj->last_recycle_time > $idleTime){
$this->unsetObj($obj);
Expand All @@ -147,7 +165,7 @@ public function gcObject(int $idleTime)
}
}
foreach ($list as $item){
$this->chan->push($item);
$this->poolChannel->push($item);
}
}

Expand Down Expand Up @@ -219,15 +237,28 @@ public function preLoad(?int $num = null):int
protected function putObject($object):bool
{
if(is_object($object)){
$hash = spl_object_hash($object);
//不在的时候说明为新对象,状态为false的时候,说明链接呗取出,允许归还
if(!isset($this->objHash[$hash]) || ($this->objHash[$hash] == false)){
if(!isset($object->__objectHash)){
return false;
}
$hash = $object->__objectHash;
//不在的时候说明为其他pool对象,不允许归还,若为true,说明已经归还,禁止重复
if(isset($this->objHash[$hash]) && ($this->objHash[$hash] == false)){
$object->last_recycle_time = time();
$this->objHash[$hash] = true;
$this->chan->push($object);
$this->poolChannel->push($object);
return true;
}
}
return false;
}

public function status()
{
return [
'created'=>$this->createdNum,
'inuse'=>$this->inuse,
'max'=>$this->getPoolConfig()->getMaxObjectNum(),
'min'=>$this->getPoolConfig()->getMinObjectNum()
];
}
}
5 changes: 5 additions & 0 deletions src/Pool/AbstractPoolObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,9 @@ function beforeUse():bool
{
return true;
}

function objectRestore()
{

}
}
7 changes: 6 additions & 1 deletion src/Pool/PoolConf.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class PoolConf

protected $extraConf = [];

function __construct(string $class)
function __construct(?string $class = null)
{
$this->class = $class;
}
Expand All @@ -33,6 +33,11 @@ public function getClass(): string
return $this->class;
}

public function setClass(string $className)
{
$this->class = $className;
}


/**
* @return float|int
Expand Down
28 changes: 27 additions & 1 deletion src/Pool/PoolManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,24 @@ class PoolManager
use Singleton;

private $pool = [];
private $defaultConfig;

function __construct()
{
$this->defaultConfig = new PoolConf();
}

function getDefaultConfig()
{
return $this->defaultConfig;
}

function register(string $className, $maxNum = 20):?PoolConf
{
$ref = new \ReflectionClass($className);
if($ref->isSubclassOf(AbstractPool::class)){
$conf = new PoolConf($className);
$conf = clone $this->defaultConfig;
$conf->setClass($className);
$conf->setMaxObjectNum($maxNum);
$this->pool[$this->generateKey($className)] = $conf;
return $conf;
Expand All @@ -47,6 +58,21 @@ function getPool(string $className):?AbstractPool
$this->pool[$key] = $obj;
return $obj;
}
}else if(class_exists($className)){
if(!$this->register($className)){
$config = clone $this->defaultConfig;
$config->setClass($className);
$pool = new class($config) extends AbstractPool{
protected function createObject()
{
// TODO: Implement createObject() method.
$className = $this->getPoolConfig()->getClass();
return new $className;
}
};
$this->pool[$key] = $pool;
}
return $this->getPool($className);
}
return null;
}
Expand Down
Loading

0 comments on commit ce362d1

Please sign in to comment.