使用場景
在 Server 程序中如果需要執(zhí)行很耗時的操作,比如一個聊天服務器發(fā)送廣播,Web服務器中發(fā)送郵件。如果直接去執(zhí)行這些函數(shù)就會阻塞當前進程,導致服務器響應變慢。例如:用戶注冊場景,完成注冊并發(fā)送激活郵件的功能,需要以下幾步:
客戶端提交 POST 數(shù)據(jù) -> 服務器獲取到數(shù)據(jù) -> 完成注冊將用戶數(shù)據(jù)寫入數(shù)據(jù)庫 -> 發(fā)送賬號激活郵件 -> 返回客戶端提示注冊成功。
這個業(yè)務邏輯是沒有問題的,但是由于發(fā)送郵件是一個耗時操作(比如2-3s)并且會同步阻塞程序的執(zhí)行,直到發(fā)送成功以后響應到客戶端提示注冊成功。這個過程中用戶從提交到最后得到注冊成功的提示估計需要4s左右,一次請求響應需要4s這肯定是不合理的!
現(xiàn)在使用 Task 異步任務投遞可以大大提升用戶體驗,大致流程:
客戶端提交 POST 數(shù)據(jù) -> 服務器獲取到數(shù)據(jù) -> 完成注冊將用戶數(shù)據(jù)寫入數(shù)據(jù)庫 -> 馬上返回客戶端提示注冊成功。
在注冊成功同時投遞一個 Task 任務 -> 異步完成郵件發(fā)送的耗時操作 (這部分時間用戶是無感知的,因為很早已經(jīng)響應回客戶端了)。
如何使用 Think-Swoole 的 Task 異步任務的步驟
定義事件監(jiān)聽類(php think make:listener 類名)。
app/event.php 文件中定義 swoole.task 的事件監(jiān)聽。
獲取到 Swoole/Server 對象調用 task 方法(參數(shù)中傳遞剛剛定義的監(jiān)聽類)。
在剛剛定義的事件監(jiān)聽類的 handle 方法中定義觸發(fā)回調邏輯代碼。
調用觸發(fā) task swoole.finish任務完成后的 finish 方法(需要才調用,非必須)。
進行演示
首先,項目根目錄創(chuàng)建郵件發(fā)送事件:
php think make:listener EmailTask
然后定義創(chuàng)建的郵件發(fā)送事件:
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 { /** * 事件監(jiān)聽處理 * * @return mixed */ public function handle($event) { echo "開始發(fā)送郵件:".time(); //模擬耗時 3 秒,測試是否在響應事件內 sleep(3); echo "郵件發(fā)送成功:".time(); // 可以調用 finish 方法通知其他事件類,通知當前異步任務已經(jīng)完成了(非必須調用) // 參數(shù) $event 是 SwooleServerTask 類的一個對象 可以調用 finish 方法觸發(fā) 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 調用驗證類驗證數(shù)據(jù) //TODO 將注冊信息插入數(shù)據(jù)庫 // 這里調用 Task 異步任務 $server -> task(applistenerEmailTask::class); // 方式二 // $manager = app(' hinkswooleManager'); // $manager -> getServer() -> task(applistenerEmailTask::class); return "注冊成功!".time(); } } }
注冊業(yè)務中,插入數(shù)據(jù)庫后,調用了發(fā)送郵件異步任務,在 EmailTask.php 模擬發(fā)送郵件需要 3 秒鐘。
開啟 Think-Swoole 服務,訪問注冊的方法,測試一下發(fā)送郵件的時間是否計入用戶注冊方法內:
可見,郵件發(fā)送的 3 秒鐘是異步進行的,用戶并無感知。
另外,還有個 swoole.finish 事件,用來通知其他事件當前異步任務已經(jīng)完成了,同樣需要創(chuàng)建事件,在 app/event.php 中定義 swoole.finish,上述示例代碼已經(jīng)演示了。
聲明:本網(wǎng)頁內容旨在傳播知識,若有侵權等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com