鏈接池的含義,不少都知道,好比mysql的數據庫鏈接是有限的,一開始鏈接mysql建立N個鏈接,放到一個容器裏,每次有請求去容器中取出,取出用完再放回去。mysql
es3demo裏,有mysql的鏈接池。sql
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進行回收。