7

一、执行异步任务

在Server程序中如果需要执行很耗时的操作,比如一个聊天服务器发送广播,Web服务器中发送邮件。如果直接去执行这些函数就会阻塞当前进程,导致服务器响应变慢。

Swoole提供了异步任务处理的功能,可以投递一个异步任务到TaskWorker进程池中执行,不影响当前请求的处理速度。

如何使用:

  • onTask
  • onFinish
  • 设置task_worker_num

二、代码实现

我们看Swoole官方文档入门指引->快速起步->Task执行异步任务

我们可以使用上一节我们封装的 websocket类中使用:

ws_task.php

<?php

/**
 * WS 优化基础类库
 */

class Ws
{
    public $ws = null;

    CONST HOST = "0.0.0.0";
    CONST PORT = 80;

    public function __construct()
    {
        // static::HOST, static::PORT
        $this->ws = new swoole_websocket_server("0.0.0.0", 80);

        $this->ws->set(
            [

               'enable_static_handler' => true, // 静态资源相关设置
               'document_root' => "/work/study/code/swoole/demo/static", // 存放静态资源路径
               'worker_num' => 2,
               'task_worker_num' => 2,
            ]
        );

        $this->ws->on("open", [$this, "onOpen"]);
        $this->ws->on("message", [$this, "onMessage"]);
        $this->ws->on("task", [$this, "onTask"]);
        $this->ws->on("finish", [$this, "onFinish"]);
        $this->ws->on("close", [$this, "onClose"]);

        $this->ws->start();
    }

    /**
     * 监听ws连接事件
     * @param $ws
     * @param $request
     */
    public function onOpen($ws, $request)
    {
        print_r("Open:" . $request->fd ."\n");
    }

    /**
     * 监听ws连接消息
     * @param $ws
     * @param $frame
     */
    public function onMessage($ws, $frame)
    {
        echo "ser-push-message:{$frame->data}\n";

        // TODO::加入我们这个业务需要执行超过 10s,所以,这里可以使用task异步来处理
        $data = [
            'task' => 1,
            'fd' => $frame->fd,
        ];

        // 投递一个任务
        $ws->task($data);
        $ws->push($frame->fd, "server-push:".date("Y-m-d H:i:s"));

    }

    /**
     * 投递任务
     *
     * @param $serv
     * @param $taskId
     * @param $workerId
     * @param $data
     */
    public function onTask($serv, $task_id, $from_id, $data)
    {
        // 耗时场景 10s
        sleep(10);

        return "on task finish";  // 告诉worker
    }

    public function onFinish($serv, $task_id, $data)
    {
        echo "taskId:{$task_id}\n";

        // 注意:此$data参数为onTask方法返回的结果:on task finish,而不是onTask方法的参数。
        echo "finish-data-success:{$data}\n";

    }

    /**
     * 监听WebSocket连接关闭事件
     *
     * @param $ws
     * @param $fd
     */
    public function onClose($ws, $fd)
    {
        echo "clientid-{$fd} is closed \n";
    }
}

$ws_obj = new Ws();

前端静态页面:
ws_task_client.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>WebSocket TEST</title>
</head>
<body>
<h1>Swoole-TEST</h1>
<script>
    var wsUrl = "ws://0.0.0.0:8880";
    var websocket = new WebSocket(wsUrl);

    // 实例化onopen对象
    websocket.onopen = function(evt){
        websocket.send("Hello-Lily"); // 发送信息给服务端
        console.log("connected-swoole-success")
    }

    // 实例化 onmessage
    websocket.onmessage = function(evt){
        console.log("ws-server-return-data"+evt.data)
    }

    // 实例化 onclose
    websocket.onclose = function(evt){
        console.log("close")
    }

    // onerror
    websocket.onerror = function (evt) {
        console.log("error:" + evt.data)
    }


</script>

</body>
</html>

我们在先开启websocket服务:

# php ws_task.php

然后在浏览器运行 ws_task_client.html 页面:

clipboard.png

这时我们再看服务端打印:

# php ws_task.php
Open:3
ser-push-message:Hello-Lily
clientid-1 is closed
taskId:0
finish-data-success:on task finish

我们可以看出,页面message及时响应,而在服务器端Task异步任务过了10s才输出来了。



Corwien
6.3k 声望1.6k 粉丝

为者常成,行者常至。