概述
任務佇列通常被我們用來處理一些非同步的耗時任務,在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 協議》,轉載必須註明作者和本文連結