getwayworker timer_Laravel + Workerman 实现多进程定时器任务

本文介绍了如何在Laravel中利用Workerman实现多进程定时任务,避免依赖Crontab或Supervisor。通过安装Workerman,创建Artisan命令,编写WorkermanTimerCommand和WorkermanTimers类,配置定时任务并在timers.php中定义执行方法,最终实现按需定时执行Laravel服务中的业务逻辑。文章还提供了启动、管理和测试定时任务的相关命令。
摘要由CSDN通过智能技术生成

前言

由于本人个人原因不太喜欢使用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的控制台命令支持

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

具体配置如下:

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类具体代码:

namespace App\Services;

class TestService

{

public function testSay()

{

var_dump("Hello Laravel and Workerman");

}

}

七、测试

输入命令php artison workerman start 启动workerman

看看有没有任务执行:

14ed803de3c1a475e2bd7425c769b2fe.png

命令:

启动:

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开发及时通信的例子,比如聊天室、弹幕什么的!

本作品采用《CC 协议》,转载必须注明作者和本文链接

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要停止定时器,可以使用`timer_settime`函数来实现。`timer_settime`函数可以设置定时器的触发时间和间隔,并且可以通过将定时器的值设置为0来停止定时器。 下面是一个示例代码,演示如何启动和停止定时器: ```c #include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include <signal.h> void timer_handler(int signum) { printf("Timer expired!\n"); } int main() { struct sigevent sev; timer_t timerid; // 创建定时器 sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIGALRM; sev.sigev_value.sival_ptr = &timerid; timer_create(CLOCK_REALTIME, &sev, &timerid); // 设置定时器的触发时间和间隔 struct itimerspec its; its.it_value.tv_sec = 1; // 第一次触发的时间间隔为1秒 its.it_value.tv_nsec = 0; its.it_interval.tv_sec = 2; // 之后每次触发的时间间隔为2秒 its.it_interval.tv_nsec = 0; timer_settime(timerid, 0, &its, NULL); // 注册信号处理函数 signal(SIGALRM, timer_handler); // 等待定时器触发 sleep(10); // 停止定时器 struct itimerspec stop_its; stop_its.it_value.tv_sec = 0; // 设置定时器的值为0,即立即停止定时器 stop_its.it_value.tv_nsec = 0; stop_its.it_interval.tv_sec = 0; stop_its.it_interval.tv_nsec = 0; timer_settime(timerid, 0, &stop_its, NULL); return 0; } ``` 在上述示例中,我们使用`timer_create`函数创建了一个定时器,并且使用`timer_settime`函数设置了定时器的触发时间和间隔。然后,注册了信号处理函数`timer_handler`来处理定时器触发的信号`SIGALRM`。 在主函数中,我们使用`sleep`函数等待定时器的触发,这里设置为10秒。之后,使用`timer_settime`函数将定时器的值设置为0,即停止定时器。 希望这个示例对你有帮助!如果有任何问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值