视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Think-Swoole之Task 异步任务
2020-11-02 17:29:20 责编:小采
文档


使用场景

在 Server 程序中如果需要执行很耗时的操作,比如一个聊天服务器发送广播,Web服务器中发送邮件。如果直接去执行这些函数就会阻塞当前进程,导致服务器响应变慢。例如:用户注册场景,完成注册并发送激活邮件的功能,需要以下几步:

客户端提交 POST 数据 -> 服务器获取到数据 -> 完成注册将用户数据写入数据库 -> 发送账号激活邮件 -> 返回客户端提示注册成功。

这个业务逻辑是没有问题的,但是由于发送邮件是一个耗时操作(比如2-3s)并且会同步阻塞程序的执行,直到发送成功以后响应到客户端提示注册成功。这个过程中用户从提交到最后得到注册成功的提示估计需要4s左右,一次请求响应需要4s这肯定是不合理的!

现在使用 Task 异步任务投递可以大大提升用户体验,大致流程:

客户端提交 POST 数据 -> 服务器获取到数据 -> 完成注册将用户数据写入数据库 -> 马上返回客户端提示注册成功。

在注册成功同时投递一个 Task 任务 -> 异步完成邮件发送的耗时操作 (这部分时间用户是无感知的,因为很早已经响应回客户端了)。

如何使用 Think-Swoole 的 Task 异步任务的步骤

定义事件监听类(php think make:listener 类名)。

app/event.php 文件中定义 swoole.task 的事件监听。

获取到 Swoole/Server 对象调用 task 方法(参数中传递刚刚定义的监听类)。

在刚刚定义的事件监听类的 handle 方法中定义触发回调逻辑代码。

调用触发 task swoole.finish任务完成后的 finish 方法(需要才调用,非必须)。

进行演示

首先,项目根目录创建邮件发送事件:

php think make:listener EmailTask

然后定义创建的邮件发送事件:

app/event.php
'listen' => [
 'AppInit' => [],
 'HttpRun' => [],
 'HttpEnd' => [],
 'LogLevel' => [],
 'LogWrite' => [],
 'swoole.task' => [
 applistenerEmailTask::class,
 ],
// 'swoole.finish' => [
// applistenerEmailTaskFinish::class,
// ],
],

其中 swoole.task 这个键名是 Task 任务固定写法不能随意命名。

接着,我们在负责用户注册的控制器内,通过 Swoole/Server 类来调用 Task 异步任务,当然,我们要先完善 EmailTask.php 的逻辑代码:

app/listener/EmailTask.php

<?php
declare (strict_types = 1);
namespace applistener;
class EmailTask
{
 /**
 * 事件监听处理
 *
 * @return mixed
 */
 public function handle($event)
{
 echo "开始发送邮件:".time();
 //模拟耗时 3 秒,测试是否在响应事件内
 sleep(3);
 echo "邮件发送成功:".time();
 // 可以调用 finish 方法通知其他事件类,通知当前异步任务已经完成了(非必须调用)
 // 参数 $event 是 SwooleServerTask 类的一个对象 可以调用 finish 方法触发 task 任务的 onFinish 事件
 // $event -> finish(applistenerEmailTaskFinish::class);
 }
}

注册方法 app/controller/Register.php

<?php
namespace appcontroller;
use appBaseController;
class Register extends BaseController
{
 public function register(SwooleServer $server)
{
 if($this -> request -> isPost()){
 $data = $this -> request -> post();
 //TODO 调用验证类验证数据
 //TODO 将注册信息插入数据库
 // 这里调用 Task 异步任务
 $server -> task(applistenerEmailTask::class);
 // 方式二
// $manager = app('	hinkswooleManager');
// $manager -> getServer() -> task(applistenerEmailTask::class);
 return "注册成功!".time();
 }
 }
}

注册业务中,插入数据库后,调用了发送邮件异步任务,在 EmailTask.php 模拟发送邮件需要 3 秒钟。

开启 Think-Swoole 服务,访问注册的方法,测试一下发送邮件的时间是否计入用户注册方法内:

可见,邮件发送的 3 秒钟是异步进行的,用户并无感知。

另外,还有个 swoole.finish 事件,用来通知其他事件当前异步任务已经完成了,同样需要创建事件,在 app/event.php 中定义 swoole.finish,上述示例代码已经演示了。

下载本文
显示全文
专题