1.work: 单进程的处理模式;
无 daemon 参数 work进程在处理完下一个消息后直接结束当前进程。当不存在新消息时,会sleep一段时间然后退出;
因为执行一次就退出了,不存在污染问题。
有 daemon 参数 work进程会循环地处理队列中的消息,直到内存超出参数配置才结束进程。当不存在新消息时,会在每次循环中sleep一段时间;
这里会造成内存污染,
代码演示效果
①.先定义一个TestS测试类
<?php
namespace app\api\job;
class TestS
{
public static $num = 0;
public function __construct(){
echo "TestS construct \n";
}
public static function testNum(){
self::$num++;
return self::$num;
}
public function __destruct() {
//在 PHP 中有一种垃圾回收机制,
//当对象不能被访问时就会自动启动垃圾回收机制,
//收回对象占用的内存空间。而析构函数正是在垃圾回收机制回收对象之前调用的
echo "TestS destructed \n";
}
}
②.再定义一个push队列和消费队列的Job类
class TestJob extends BaseJob
{
public function sendJob(){
$job='app\api\job\TestJob@doJob';
$data=[
'rand'=>rand(100000,999999),
'time'=>date("Y-m-d H:i:s"),
];
for ($i=0;$i<5;$i++){
$res=Queue::push($job,$data,'test');
if($res){
echo ' push success ';
}else{
echo ' push fail ';
}
}
}
public function doJob(Job $job,$data){
echo "------------------------\n";
$testS = new TestS();
echo "testS object address:".spl_object_hash($testS)."\n";; // 输出的内存地址 每次都不一样,说明每次调用都会重新new一个新的,之前的也会被系统回收掉
TestS::testNum();
echo "num:".TestS::$num.",address:".memory_get_usage(TestS::$num).",processId:".getmypid()."\n";
$job->delete();
(new \app\common\model\QueueLog())->log($job->getQueue(),$job->getName(),$data);
}
}
③.执行队列代码
//先调用sendJob方法生产队列
(new \app\api\job\TestJob())->sendJob();
//windows cmd 命令执行队列进行消费,注意需要进入到thinkphp的根目录下执行,具体参数根据自己情况配置
D:\phpstudy_pro\Extensions\php\php5.6.9nts/php think queue:work --sleep=3 --tries=10 --daemon --queue test
④.执行结果如下
------------------------
TestS construct //$testS = new TestS(); new 一个对象很正常的调用了构造方法
testS object address:000000001b40ea86000000007ab35548 //打印出$testS 的内存地址
num:1,address:6815744,processId:23148 //静态变量 num进行了累加,但是内存地址不一样,应该是重新分配了内存地址,进程id都一样说明是同一个进程执行的
TestS destructed //虽然$testS 的内存地址都一样但是确实是执行了销毁函数
Processed: app\api\job\TestJob@doJob
------------------------
TestS construct
testS object address:000000001b40ea86000000007ab35548
num:2,address:8126464,processId:23148
TestS destructed
Processed: app\api\job\TestJob@doJob
------------------------
TestS construct
testS object address:000000001b40ea86000000007ab35548
num:3,address:8126464,processId:23148
TestS destructed
Processed: app\api\job\TestJob@doJob
从上面的三次执行结果可以看出,每次消费完一个任务后,通过new实例化的对象都会销毁,因为你每次都new一个新的,之前的对象就没有变量再进行引用,所以会自动销毁
num的静态变量值会每次进行增加,因为每次调用都进行了num++操作,内存地址有时候会变有时候没变,这个应该是php的内部逻辑问题,不再探究,有兴趣的可以在下面留言
2.listen: 父进程 + 子进程 的处理模式;
会在所在的父进程会创建一个单次执行模式的work子进程,并通过该work子进程来处理队列中的下一个消息,当这个work子进程退出之后;
所在的父进程会监听到该子进程的退出信号,并重新创建一个新的单次执行的work子进程;
通过上面的解释可以理解,每次都新开一个子进程,那么上一个子进程的所有内存空间都会被释放
代码不变执行消费命令代码如下:
D:\phpstudy_pro\Extensions\php\php5.6.9nts/php think queue:listen --sleep=3 --tries=10 --queue test
结果显示如下:
TestS construct
testS object address:00000000558bd66800000000539bf6a0 //new 对象的内存地址不一样
num:1,address:6815744,processId:9240 //num变量的值都是1,没有进行累加增加,但是内存地址一样,只是重新分配了值而已,这个不影响,子进程id不一样
TestS destructed
Processed: app\api\job\TestJob@doJob
------------------------
TestS construct
testS object address:0000000030a78add000000004d467751
num:1,address:6815744,processId:20840
TestS destructed
Processed: app\api\job\TestJob@doJob
------------------------
TestS construct
testS object address:000000004c847d9d000000000c00640c
num:1,address:6815744,processId:7904
TestS destructed
Processed: app\api\job\TestJob@doJob
所以listen模式,除了每次新开和关闭子进程比较浪费资源之外,其他还是比较安全的,如果并发不是很高的情况下还是建议linsten模式,至少不会出现内存泄漏,变量污染的问题。
以上只是个人理解,如果不对的地方欢迎大家指正,或者你有更好的见解也可以留言