前言
由於本人個人原因不太喜歡使用Linux的Crontab或者使用Supervisor去執行php的一些非同步程式。
但是有了workerman的加持,我們可以使用workerman的一些方法特性去實現純php版的非同步功能。
因為workerman這個框架自身也是純PHP實現的高效能非同步PHP socket即時通訊框架,php加持php豈不美哉?
(PS:workerman死忠粉)
準備工作
Laravel版本:6.0
Workerman版本:4.0
workerman的執行環境需要安裝pcntl和posix擴充套件。
我這裡使用的是laravel的整合docker環境 laradock
是可以直接使用的
Workerman環境具體可以訪問:http://doc.workerman.net/install/install.h...
Laradock環境https://laradock.io/
具體實現
一、安裝workerman
composer require workerman/workerman
二、編寫Artisan控制檯命令方便呼叫workerman
php artisan make:command WorkermanTimerCommand
可以看到在laravel的app\Console\Commands目錄下生產了一個WorkermanTimerCommand.php檔案。
三、接著我們開始編寫workerman的控制檯命令支援
<?php
namespace App\Console\Commands;
use App\Listens\WorkermanTimers;
use Illuminate\Console\Command;
use Workerman\Worker;
class WorkermanTimerCommand extends Command
{
/**
* 控制檯命令的名稱和引數.
*
* @var string
*/
protected $signature = 'workerman {action} {--d}';
/**
* 控制檯命令描述.
*
* @var string
*/
protected $description = 'workerman的多程式定時任務';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
global $argv;
$action = $this->argument('action');
$argv[0] = 'wk';
$argv[1] = $action;
$argv[2] = $this->option('d') ? '-d' : '';
$this->startServer();
}
/**
* 啟動workerman服務
*/
public function startServer()
{
$worker = new Worker();
// 服務名稱.
$worker->name = 'laravel timer';
// 啟動多少個程式數量,這裡大家靈活配置,可以參考workerman的文件.
$worker->count = 4;
// 當workerman的程式啟動時的回撥方法.
$worker->onWorkerStart = [WorkermanTimers::class, 'onWorkerStart'];
// 當workerman的程式關閉時的回撥方法.
$worker->onClose = [WorkermanTimers::class, 'onClose'];
Worker::runAll();
}
}
可以看到在上面的startServer
方法裡,我們為onWorkerStart
和onClose
分別註冊回撥到了WorkermanTimers
類裡面的onWorkerStart
和onWorkerStart
方法。
這裡的意思是當workerman裡面的程式啟動的時候,會呼叫WorkermanTimers
類裡面對應的方法!
那我們來看看這個WorkermanTimers
類究竟需要幹一些什麼!
四、編寫定時器任務分發類(WorkermanTimers)
我們現在app目錄下新建一個Listens
目錄,並建立WorkermanTimers
類
WorkermanTimers
類具體程式碼:
namespace App\Listens;
use Workerman\Lib\Timer;
class WorkermanTimers
{
/**
* 服務程式啟動時
* @param $businessWorker
*/
public static function onWorkerStart($businessWorker)
{
// 拿到當前程式的id編號.
$workid = $businessWorker->id;
// 獲取所有定時器任務配置.
$timedTask = config('timers');
if (is_array($timedTask)) {
// 迴圈檢測任務繫結.
foreach ($timedTask as $key => $value) {
// 繫結任務程式.
if ($value['worker_id'] == $workid) {
Timer::add($value['time'], $value['func']);
}
}
}
}
/**
* 服務程式結束時
* @param $client_id
*/
public static function onClose($client_id)
{
}
}
解釋:
以上onWorkerStart
方法就是workerman每個程式剛啟動的時候
會回撥過來當前程式的屬性$businessWorker
我們在WorkermanTimerCommand
裡面定義的程式數count=4
,就是4個程式。也就是說onWorkerStart
方法會被呼叫四次,因為多程式裡每個程式相互隔離,所以每次我們拿到的$businessWorker->id
都會不一樣。
worker程式的id編號,範圍為0到$worker->count-1,所以每次$businessWorker->id
編號應該是0,1,2,3
所以我們迴圈定義的timers
配置,判斷每個配置繫結的程式編號如果和當前的程式編號一致,我們就為當前程式增加一個定時器!
可能各位看官有疑問了,timers
的配置在哪呢?
我們接著往下走
五、在config/
目錄下新增一個timers.php
具體配置如下:
<?php
return [
// 定時任務名稱.
'say' => [
'worker_id' => 1, // 需要繫結的程式id.
'time' => 5, // 時間間隔 秒為單位.
'func' => 'Facades\App\Services\TestService::testSay', // 定時執行的方法.
],
/* 'eat' => [
'worker_id' => 2, // 需要繫結的程式id.
'time' => 10, // 時間間隔 秒為單位.
'func' => 'Facades\App\Services\TestService::testEat', // 定時執行的方法.
]*/
];
timers.php
返回的是一個多維資料結構的配置,
陣列一級元素代表這個定時任務的名稱(為了區分和理解),
陣列二級元素worker_id
代表我們需要繫結到哪個程式
陣列二級元素time
表示時間間隔,多少秒執行一次
陣列二級元素func
代表要執行哪個方法
在結合上面的WorkermanTimers
類去看,就可以理解為:
任務:say
繫結在程式編號為1
的worker上面,每5秒就會執行一次\App\Services\TestService
類裡面的testSay
方法
在laravel裡面,名稱空間前面加上Facades\
就可以靜態呼叫該類的方法,這部分的概念大家可以去看看laravel文件
六、編寫定時任務類
我們在app
目錄下新建一個Services
資料夾,並且新增一個TestService
類
TestService
類具體程式碼:
<?php
namespace App\Services;
class TestService
{
public function testSay()
{
var_dump("Hello Laravel and Workerman");
}
}
七、測試
輸入命令php artison workerman start
啟動workerman
看看有沒有任務執行:
命令:
啟動:
php artisan workerman start
啟動常駐記憶體:
php artisan workerman start --d
其他命令:
php artisan workerman reload //重新載入配置
php artisan workerman reload //重啟workerman
php artisan workerman stop //停止workerman
總結
流程:
1.當workerman的每個程式啟動後,會回撥給WorkermanTimers
類的onWorkerStart
方法
2.onWorkerStart
會載入所有定時任務的配置,然後去迴圈繫結任務類
3.新增workerman定時間並繫結任務類方法!
4.每個程式繫結一個定時任務,當然也可以一個程式繫結多個定時器任務,具體取決於你怎麼在timers.php
裡面配置
參考文件
其他
workerman是一款底層設計非常優秀的框架,純php實現高效能常駐記憶體特性。
workerman能做的事情也遠遠不止於此,還有很多例如:IM、遊戲、物聯網等等功能等你去探索!
當優雅的Laravel
遇上 效能強悍得 Workerman
會發生點什麼呢?
如果大家有興趣的話後面我可以在寫一些Laravel
結合Workerman
開發及時通訊的例子,比如聊天室、彈幕什麼的!
原文地址:https://utf8.hk/archives/workerman_laravel...
本作品採用《CC 協議》,轉載必須註明作者和本文連結