使用場景
#在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' => [ app\listener\EmailTask::class, ], // 'swoole.finish' => [ // app\listener\EmailTaskFinish::class, // ], ],
其中swoole.task 這個鍵名是Task 任務固定寫法不能隨意命名。
接著,我們在負責使用者註冊的控制器內,透過Swoole/Server 類別來呼叫Task 非同步任務,當然,我們要先完善EmailTask.php 的邏輯程式碼:
app/ listener/EmailTask.php
<?php declare (strict_types = 1); namespace app\listener; class EmailTask { /** * 事件监听处理 * * @return mixed */ public function handle($event) { echo "开始发送邮件:".time(); //模拟耗时 3 秒,测试是否在响应事件内 sleep(3); echo "邮件发送成功:".time(); // 可以调用 finish 方法通知其他事件类,通知当前异步任务已经完成了(非必须调用) // 参数 $event 是 Swoole\Server\Task 类的一个对象 可以调用 finish 方法触发 task 任务的 onFinish 事件 // $event -> finish(\app\listener\EmailTaskFinish::class); } }
註冊方法app/controller/Register.php
<?php namespace app\controller; use app\BaseController; class Register extends BaseController { public function register(\Swoole\Server $server) { if($this -> request -> isPost()){ $data = $this -> request -> post(); //TODO 调用验证类验证数据 //TODO 将注册信息插入数据库 // 这里调用 Task 异步任务 $server -> task(\app\listener\EmailTask::class); // 方式二 // $manager = app('\think\swoole\Manager'); // $manager -> getServer() -> task(\app\listener\EmailTask::class); return "注册成功!".time(); } } }
註冊業務中,插入資料庫後,呼叫了發送郵件非同步任務,在EmailTask.php 模擬發送郵件需要3 秒鐘。
開啟Think-Swoole 服務,存取註冊的方法,測試一下發送郵件的時間是否計入用戶註冊方法內:
可見,郵件發送的3 秒鐘是異步進行的,使用者並無感知。
另外,還有個swoole.finish 事件,用來通知其他事件當前非同步任務已經完成了,同樣需要建立事件,在app/event.php 中定義swoole.finish,上述範例程式碼已經示範了。
以上是Think-Swoole之Task 非同步任務的詳細內容。更多資訊請關注PHP中文網其他相關文章!