在Server程序中如果需要执行很耗时的操作,比如一个聊天服务器发送广播,Web服务器中发送邮件、短信。如果直接去执行这些函数就会阻塞当前进程,导致服务器响应变慢。
Swoole提供了异步任务处理的功能,可以投递一个异步任务到TaskWorker进程池中执行,不影响当前请求的处理速度。
实现
基于第一个WS服务器,只需要增加onTask和onFinish 2个事件回调函数即可,onFinish事件接收onTask事件执行完毕后的返回值。另外需要设置task进程数量,可以根据任务的耗时和任务量配置适量的task进程。
场景
当收到来自客户端的消息,执行一个耗时10秒的代码逻辑(如发送邮件),再去返回客户端消息,这个时候客户端就需要等待至少10秒,用户体验是非常差的。
onTask事件的编写,我们可以查看官方文档
<?php
class WS {
public $server;
public function __construct() {
$this->server = new Swoole\WebSocket\Server('0.0.0.0', 8812);
$this->server->set([
'worker_num' => 2,
'task_worker_num' => 2
]);
$this->server->on('open', [$this, 'onOpen']);
$this->server->on('message', [$this, 'onMessage']);
$this->server->on('task', [$this, 'onTask']);
$this->server->on('finish', [$this, 'onFinish']);
$this->server->on('close', [$this, 'onClose']);
$this->server->start();
}
public function onOpen($server,$request)
{
echo "server: handshake success with fd{$request->fd}\n";
// todo 10s
$data = [
'task' => 1,
'fd' => $request->fd
];
$server->task($data);
$server->push($request->fd,'server-push:'.date('Y-m-d H:i:s'));
}
public function onMessage($server,$frame)
{
echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
$server->push($frame->fd, "this is server");
}
public function onTask($server, $taskId, $workerId, $data)
{
print_r($data);
// 耗时场景 10s
sleep(10);
return 'on task 10s finish'; // 告诉worker
}
public function onFinish($server, $taskId, $data)
{
echo "taskId:{$taskId}\n";
echo "finish-data-success:{$data}\n"
}
public function onClose($server,$fd)
{
echo "client {$fd} closed\n";
}
}
$obj = new WS();
测试
开启http服务,ws服务。
浏览器访问http://127.0.0.1:8811/ws_client.html。通过HTTP服务启动ws客户端连接WebSocket服务,进入浏览器控制台可以看到,onFinish中的逻辑是在最后执行的,而在onOpen事件中,在投递task任务之后的逻辑并没有等Task的逻辑执行完再执行,这是因为Swoole的Task是异步处理的。
HTTP服务,TCP都是可以基于这种形式做Task任务投放的。