如何写一个任务队列
概述
任务队列通常被我们用来处理一些异步的耗时任务,在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的例子在任何平台都是可以用的。
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: