首页 > 代码库 > PHP 异步使用swoole的可行性测试

PHP 异步使用swoole的可行性测试

  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的可行性测试