連接池的含義,很多都知道,比如mysql的數據庫連接是有限的,一開始連接mysql創建N個連接,放到一個容器里,每次有請求去容器中取出,取出用完再放回去。
es3demo里,有mysql的連接池。
EasySwooleEvent::30行,執行initialize方法會注冊一個MysqlPool::class
MysqlPool是繼承於AbstractPool的只實現了createObject方法來創建mysql連接對象
AbstractPool這個抽象類,里我們分析下2個函數getObj和recycleObj。
EasySwoole\Component\Pool\AbstractPool::35和57行
getObj函數,當協程的chan還是空的時候不一定指的是初始化,可能是連接池的mysql連接都被用光了還沒被回收,舉個例子,如果我的連接池容量是10,現在10個用戶同時訪問我,我從連接池取出了10個現在連接池空了,等10個人隨便某人用完了回收,連接池又不空了。這樣就能理解為什么還
要判斷當前創建的數量是否大於連接池容量。如果沒有大於說明現在還可以繼續往容器里防止連接對象而不會溢出連接池容量。其他情況就直接嘗試從chan取出連接池對象。如果獲取失敗也是允許的。並發場景下獲取不到連接池能容忍。
public function getObj(float $timeout = 0.1) { //懶惰創建模式 $obj = null; if($this->chan->isEmpty()){ //如果還沒有達到最大連接數,則嘗試進行創建 if($this->createdNum < $this->max){ $this->createdNum++; $obj = $this->createObject(); if(!is_object($obj)){ $this->createdNum--; //創建失敗,同樣進入調度等待 $obj = $this->chan->pop($timeout); } }else{ $obj = $this->chan->pop($timeout); } }else{ $obj = $this->chan->pop($timeout); } //對對象進行標記處理 if(is_object($obj)){ $key = spl_object_hash($obj); //標記這個對象已經出隊列了 $this->objHash[$key] = true; $obj->last_use_time = time(); return $obj; }else{ return null; } }
回收的話就簡單了,把獲取到連接池對象塞回去chan->push
public function recycleObj($obj):bool { if(is_object($obj)){ //防止一個對象被重復入隊列。 $key = spl_object_hash($obj); if(isset($this->objHash[$key])){ //標記這個對象已經入隊列了 unset($this->objHash[$key]); if($obj instanceof PoolObjectInterface){ $obj->objectRestore(); } $obj->last_recycle_time = time(); $this->chan->push($obj); return true; }else{ return false; } }else{ return false; } }
示例demo是這樣調用的
App\HttpController\Api1構造方法會去從連接池里獲取數據庫連接,然后afterAction會去調用recycleObject進行回收。
