如何写一个任务队列
26

概述

任务队列通常被我们用来处理一些异步的耗时任务,在laravel中具体的用法可以看文档,那么任务队列是如何工作的呢?简而言之,它也是一个生产者消费者模型,队列处理器充当消费者不断消费任务,任务生产者不断向队列中塞任务。基于这种思想,我们也可以自己尝试着写一个。

消费者

既然如此,我们首先需要一个处理(消费)任务的消费者。核心代码如下:

    public function run()
    { 
        while(true){
            $taskList = $this->getTaskList();
            if(empty($taskList)){
                $this->stop();
            }
            $this->consume($taskList);
        }
    }

    protected function consume($taskList)
    {
        while(!empty($taskList)){
            $job = array_pop($taskList);
            $job = unserialize($job);
            $job->handle();
        }
    }

    protected function stop()
    {
        posix_kill($this->pid,SIGSTOP);
    }

消费者说明
利用一个死循环,在任务队列不为空的时候不断消耗队列,为空的时候则停止任务处理器进程,防止CPU空转浪费资源。在laravel的队列代码中使用的是sleep来间歇性停止进程,而不是采用上述代码中的这种SIGSTOP方式。

生产者

接下来我们就继续写一个生产者,例子中存储任务使用的是redis,核心代码如下:


    public function pushTask()
    {
        //store job in the redis or other database
        $this->storeTask();
        $this->wakeupWorker();
    }

    protected function storeTask()
    {
        //store job in the redis or other database like this
        $redis = $this->getTaskContainer();
        $redis->lpush("task_list",serialize($this->job));
        //job must implements interface hanler
    }

    protected function wakeupWorker()
    {
        posix_kill($this->workerPid,SIGCONT);
    }

生产者说明
当有任务到来的时候,把任务持久化到某个任务容器中,然后唤醒消费者进程,使其消费任务。

结语

具体的代码示例,见 代码示例,测试用例只能运行在linux环境中(因为借助了linux信号机制),测试用例经过测试全部可用,测试用例中使用了redis存储任务,可根据自己需要使用文件或者mysql数据库等其他方式存储。
laravel中的消费者使用了sleep的方式间歇性唤醒自己去检查队列是否有可消费的对象,而不用借助于生产者信号唤醒,一定程度上降低了耦合性,生产者只需向任务队列中塞任务即可,但是也会带来一个问题就是如果长久没有任务到来,生产者依然还是不断地要唤醒自己,再挂起自己,这种也是某种形式的浪费资源。但是laravel的例子在任何平台都是可以用的。

每天进步一点点

本帖由系统于 10个月前 自动加精
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
讨论数量: 3

laravel的队列,你这个,还有mq的消息队列有区别吗?

10个月前

@梦康 这是个好问题,而且是个大问题,我大概说下我自己的理解吧(不保证权威性正确性):mq=Message Queue就是指消息队列,而我写的是任务队列的模型例子,既然都是队列那么都遵循FIFO,比如都是基于生产者-消费者模型的。消息队列着眼于“消息”的传递,用于解决应用之间的通信问题,比方两个进程间通信,分布式应用间通信;任务队列着眼于“任务”的处理,比方说平常的我们注册了一个网站之后要给用户发邮件,发短信等,这种耗时任务,我们不是很关心及时结果,可以异步执行,这里我们就把这个操作丢到任务队列中处理,任务队列主要的目的就是处理任务。
关于我的这个和 laravel 里面的那个,源码你都可以拿到,我这个只是探究性的小轮子,正如 十个你需要在 PHP 7 中避免的坑 这里第9点说到的:不要重复造轮子,如果应用到项目中,肯定是使用成熟的产品为佳,但是探究性地拆下轮子自己改改,加深对框架的理解也是有好处的,关于二者的最主要区别我也写在上文的结语里面了。

10个月前

@wilson_yang 哈,刚好接触mq,有点纳闷。豁然开朗了

10个月前

  • 请注意单词拼写,以及中英文排版,参考此页
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`, 更多语法请见这里 Markdown 语法
  • 支持表情,使用方法请见 Emoji 自动补全来咯,可用的 Emoji 请见 :metal: :point_right: Emoji 列表 :star: :sparkles:
  • 上传图片, 支持拖拽和剪切板黏贴上传, 格式限制 - jpg, png, gif
  • 发布框支持本地存储功能,会在内容变更时保存,「提交」按钮点击时清空
  请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!