標籤:網路通訊 網路 finish ted web exception array 時間 tor
PHP的非同步、並行、高效能網路通訊引擎swoole架構,在一開始我就比較注意,原因無他,php在swoole未出的情況下在多線程調度上確實算得上沒有較好的解決方案。
我以系統的註冊流程舉例,在比較複雜的系統中,使用者建立,需要同時做出很多相應的其他的操作,比如關聯其他的業務表,發送郵件等操作是比較耗時的,但是其實又和登陸資訊的註冊毫無關係,一般情況我們會丟到佇列服務中去。然後通過使用定時任務去處理使用者建立後的其他非同步作業。那既然前景和舊的解決方案已經提出來,那麼使用swoole能做得更好嗎?
這裡我使用的是swoole的TCP伺服器作為郵件非同步伺服器開啟task來作為非同步作業,然後web端調用swoole的TCP用戶端發送後不等待recv接收直接關閉。下面貼出我的執行代碼
TCP的伺服器
<?php/** * Created by PhpStorm. * User: xujun * Date: 2017/7/28 * Time: 22:26 */class TcpService{ public function run(){ $serv = new swoole_server("127.0.0.1", 9502); //設定非同步任務的背景工作處理序數量 $serv->set(array(‘task_worker_num‘ => 4)); $serv->on(‘receive‘, function($serv, $fd, $from_id, $data) { //投遞非同步任務 $task_id = $serv->task($data); echo "非同步任務id=$task_id\n"; });//處理非同步任務 $serv->on(‘task‘, function ($serv, $task_id, $from_id, $data) { echo "非同步任務[id=$task_id]".PHP_EOL; //返回任務執行的結果 //為了測試時間的延時性這裡我做了大數組的特性 try{ //會記憶體超出 $arr = array_fill(0,100000,0); foreach ($arr as $v){ //echo $v; } foreach ($arr as $v){ //echo $v; } $num = 0; while(true){ if($num>2147483647){ break; } $num++; } }catch(Exception $e){ $e->getMessage(); } $serv->finish("[".date(‘Y-m-d H:i:s‘)."]{$data}郵箱已經發送"); });//處理非同步任務的結果 $serv->on(‘finish‘, function ($serv, $task_id, $data) { echo "非同步任務[$task_id] 完成: $data".PHP_EOL; }); $serv->start(); }}$a = new TcpService();$a->run();
下面是web用戶端的指令碼
<?php//處理管道class Cross{ public function process(array $stages, $payload) { foreach ($stages as $stage) { $payload = call_user_func($stage, $payload); } return $payload; }}//管道class Pipeline{ private $stages = []; public function __construct(array $stages = []) { foreach ($stages as $stage) { if (false === is_callable($stage)) { throw new Exception(‘All stages should be callable.‘); } } $this->stages = $stages; $this->processor =new Cross; } /** * @inheritdoc */ public function pipe(callable $stage) { $this->stages[] = $stage; return $this; } /** * Process the payload. * * @param $payload * * @return mixed */ public function process($payload) { return $this->processor->process($this->stages, $payload); }}$pie = new Pipeline();$pie->pipe(function($payload){ echo ‘系統使用者‘.$payload.‘資料驗證成功<br>‘; return $payload;})->pipe(function($payload){ echo ‘系統使用者資料產生<br>‘; return $payload;})->pipe(function($payload){ echo ‘非同步開始發送驗證郵件<br>‘; //建立swoole用戶端 try{ $client = new swoole_client(SWOOLE_SOCK_TCP);//串連到伺服器 if (!$client->connect(‘127.0.0.1‘, 9502, 0.5)) { die("connect failed."); }//向伺服器發送資料 if (! $client->send("系統發送給使用者{$payload}一封驗證郵件")) { die("send failed."); } $client->close(); }catch (Exception $e){ echo $e->getMessage(); } return $payload;})->pipe(function($payload){ echo date(‘Y-m-d H:i:s‘).‘系統成功建立使用者<br>‘;});$pie->process(‘我是09‘);
測試順序是,先開啟tcp伺服器,然後訪問web指令碼
執行結果
web指令碼
TCP伺服器的處理值
從結果上來說,驗證郵件發送並沒有阻塞到web指令碼,也就是滿足我們的非同步要求。
PHP 非同步使用swoole的可行性測試