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 "; }); //处理异步任务 $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脚本,也就是满足我们的异步要求。