php +swoole實現非同步任務佇列
阿新 • • 發佈:2019-02-08
假如要發100封郵件,for迴圈100遍,使用者直接揭竿而起,什麼破網站!
但實際上,我們很可能有超過1萬的郵件。怎麼處理這個延遲的問題?
答案就是用非同步。把“發郵件”這個操作封裝,然後後臺非同步地執行1萬遍。這樣的話,使用者提交網頁後,他所等待的時間只是“把發郵件任務請求推送進佇列裡”的時間。而我們的後臺服務將在使用者看不見的地方跑。
在實現“非同步佇列”這點上,有人採用MySQL表或者redis來存放待發送的郵件,然後,每分鐘定時讀取待發送列表,然後處理。這便是定時非同步任務佇列。但當前提交的任務要一分鐘後才能執行,在某些實時性要求高的應用場景裡還是不快,比如傳送簡訊的場景,只要一提交任務,便要馬上執行,使用者不需要等待返回結果。
但實際上,我們很可能有超過1萬的郵件。怎麼處理這個延遲的問題?
答案就是用非同步。把“發郵件”這個操作封裝,然後後臺非同步地執行1萬遍。這樣的話,使用者提交網頁後,他所等待的時間只是“把發郵件任務請求推送進佇列裡”的時間。而我們的後臺服務將在使用者看不見的地方跑。
在實現“非同步佇列”這點上,有人採用MySQL表或者redis來存放待發送的郵件,然後,每分鐘定時讀取待發送列表,然後處理。這便是定時非同步任務佇列。但當前提交的任務要一分鐘後才能執行,在某些實時性要求高的應用場景裡還是不快,比如傳送簡訊的場景,只要一提交任務,便要馬上執行,使用者不需要等待返回結果。
以下將探討用php擴充套件swoole實現實時非同步任務佇列傳送簡訊的方案。
服務端
第一步:建立tcp伺服器
第二步:設定伺服器的相關屬性
第三步:設定服務端的相關回調函式處理任務
具體程式碼如下:tcp_server.php
<?php class Server{ private $serv; public function __construct(){ $this->serv = new swoole_server("0.0.0.0",9501); $this->serv->set( array( 'worker_num' => 1, //一般設定為伺服器CPU數的1-4倍 'daemonize' => 1, //以守護程序執行 'max_request' => 10000, 'dispatch_mode' => 2, 'task_worker_num' => 8, //task程序的數量 "task_ipc_mode " => 3, //使用訊息佇列通訊,並設定為爭搶模式 "log_file" => "log/taskqueueu.log", ) ); $this->serv->on('Receive',array($this,'onReceive')); $this->serv->on('Task',array($this,'onTask')); $this->serv->on('Finish',array($this,'onFinish')); $this->serv->start(); } public function onReceive(swoole_server $serv, $fd, $from_id, $data){ $serv->task($data); } public function onTask($serv, $task_id, $from_id, $data){ $data = json_decode($data,true); if(!empty($data)){ return $this->sendsms($data['mobile'],$data['message']); } } public function onFinish($serv, $task_id, $data){ echo "Task {$task_id} finish\n"; } public function sendsms($mobile,$text) { $timestamp = date("Y-m-d H-i-s"); $pid = "888888888"; $send_sign = md5($pid.$timestamp."abcdefghijklmnopqrstuvwxyz"); $post_data = array(); $post_data['partner_id'] = $pid; $post_data['timestamp'] =$timestamp; $post_data['mobile'] = $mobile; $post_data['message'] = $text; $post_data['sign'] = $send_sign; $url='http://182.92.149.100/sendsms'; $o=""; foreach ($post_data as $k=>$v) { $o.= "$k=".urlencode($v)."&"; } $post_data=substr($o,0,-1); $ch = curl_init(); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_URL,$url); //為了支援cookie //curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookie.txt'); curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $result = curl_exec($ch); if(strpos($result,"success")!==false) { $outstr=1; } else { $outstr=502; } return $outstr; } } $server = new Server(); ?>
客戶端
啟動後端服務後,客戶端首先建立tcp客戶端伺服器,然後連線tcp後端伺服器,並向後端tcp伺服器傳送資料,具體程式碼如下:client.php
<?php class Client{ public $client; public function __construct(){ $this->client= new swoole_client(SWOOLE_SOCK_TCP);//默認同步tcp客戶端,新增引數SWOOLE_SOCK_ASYNC為非同步 } public function connect(){ if(!$this->client->connect('127.0.0.1',9501,1)){ throw new Exception(sprintf('Swoole Error: %s', $this->client->errCode)); } } public function send($data){ if($this->client->isConnected()){ $data = json_encode($data); //print $data; if($this->client->send($data)){ return 1; }else{ throw new Exception(sprintf('Swoole Error: %s', $this->client->errCode)); } }else{ throw new Exception('Swoole Server does not connected.'); } } public function close(){ $this->client->close(); } } $client= new Client(); $client->connect(); $data=array( 'mobile'=>'18511487955', 'message'=>'you mobile 18511487955' ); if($client->send($data)){ echo 'succ'; }else{ echo 'fail'; } ?>