環(huán)境說明: 系統(tǒng):Ubuntu14.04 (安裝教程包括CentOS6.5)
PHP版本:PHP-5.5.10
swoole版本:1.7.6-stable
上一章已經(jīng)簡(jiǎn)單介紹了如何寫一個(gè)簡(jiǎn)單的Echo服務(wù)器,并了解了onReceive等幾個(gè)核心回調(diào)函數(shù)的使用方法。這一章,我將介紹如何使用Swoole的異步任務(wù)Task。
Swoole的業(yè)務(wù)邏輯部分是同步阻塞運(yùn)行的,如果遇到一些耗時(shí)較大的操作,例如訪問數(shù)據(jù)庫、廣播消息等,就會(huì)影響服務(wù)器的響應(yīng)速度。因此Swoole提供了Task功能,將這些耗時(shí)操作放到另外的進(jìn)程去處理,當(dāng)前進(jìn)程繼續(xù)執(zhí)行后面的邏輯。
開啟Task功能只需要在swoole_server的配置項(xiàng)中添加task_worker_num一項(xiàng)即可,如下:
$serv->set(array(
'task_worker_num' => 8
));
即可開啟task功能。此外,必須給swoole_server綁定兩個(gè)回調(diào)函數(shù):onTask和onFinish。這兩個(gè)回調(diào)函數(shù)分別用于執(zhí)行Task任務(wù)和處理Task任務(wù)的返回結(jié)果。
首先是發(fā)起一個(gè)Task,代碼如下:
public function onReceive( swoole_server $serv, $fd, $from_id, $data ) {
echo "Get Message From Client {$fd}:{$data}\n";
// send a task to task worker.
$param = array(
'fd' => $fd
);
// start a task
$serv->task( json_encode( $param ) );
echo "Continue Handle Worker\n";
}
可以看到,發(fā)起一個(gè)任務(wù)時(shí),只需通過swoole_server對(duì)象調(diào)用task函數(shù)即可發(fā)起一個(gè)任務(wù)。swoole內(nèi)部會(huì)將這個(gè)請(qǐng)求投遞給task_worker,而當(dāng)前Worker進(jìn)程會(huì)繼續(xù)執(zhí)行。
當(dāng)一個(gè)任務(wù)發(fā)起后,task_worker進(jìn)程會(huì)響應(yīng)onTask回調(diào)函數(shù),如下:
public function onTask($serv,$task_id,$from_id, $data) {
echo "This Task {$task_id} from Worker {$from_id}\n";
echo "Data: {$data}\n";
for($i = 0 ; $i < 10 ; $i ++ ) {
sleep(1);
echo "Task {$task_id} Handle {$i} times...\n";
}
$fd = json_decode( $data , true )['fd'];
$serv->send( $fd , "Data in Task {$task_id}");
return "Task {$task_id}'s result";
}
這里我用sleep函數(shù)和循環(huán)模擬了一個(gè)長(zhǎng)耗時(shí)任務(wù)。在onTask回調(diào)中,我們通過task_id和from_id(也就是worker_id)來區(qū)分不同進(jìn)程投遞的不同task。當(dāng)一個(gè)task執(zhí)行結(jié)束后,通過return一個(gè)字符串將執(zhí)行結(jié)果返回給Worker進(jìn)程。Worker進(jìn)程將通過onFinish回調(diào)函數(shù)接收這個(gè)處理結(jié)果。
下面來看onFinish回調(diào):
public function onFinish($serv,$task_id, $data) {
echo "Task {$task_id} finish\n";
echo "Result: {$data}\n";
}
在onFinish回調(diào)中,會(huì)接收到Task任務(wù)的處理結(jié)果$data。在這里處理這個(gè)返回結(jié)果即可。 (Tip:?可以通過在傳遞的data中存放fd、buff等數(shù)據(jù),來延續(xù)投遞Task之前的工作)
之所以在這里講解如何使用swoole_client是因?yàn)椋趯懛?wù)端代碼的時(shí)候,不可避免的需要用到客戶端來進(jìn)行測(cè)試。swoole提供了swoole_client用于編寫測(cè)試客戶端,下面我將講解如何使用這個(gè)工具。
swoole_client有兩種工作模式:同步阻塞模式和異步回調(diào)模式。其中,同步阻塞模式在上一章中已經(jīng)給出示例,其使用和一般的socket基本無異。因此,我將重點(diǎn)講解swoole_client的異步回調(diào)模式。
創(chuàng)建一個(gè)異步client的代碼如下:
$client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);
其中,SWOOLE_SOCK_ASYNC選項(xiàng)即表明創(chuàng)建一個(gè)異步client。
既然是異步,那當(dāng)然需要回調(diào)函數(shù)。swoole_client一共有四個(gè)回調(diào)函數(shù),如下:
$client->on("connect", function($cli) {
$cli->send("hello world\n");
});
$client->on("receive", function($cli, $data){
echo "Received: ".$data."\n";
});
$client->on("error", function($cli){
echo "Connect failed\n";
});
$client->on("close", function($cli){
echo "Connection close\n";
});
這幾個(gè)回調(diào)函數(shù)的作用基本和swoole_server類似,只有參數(shù)不同,因此不再贅述。?點(diǎn)此查看完整示例
我用swoole擴(kuò)展寫了一個(gè)簡(jiǎn)單的聊天室Demo(點(diǎn)此查看) 這個(gè)Demo雖然用到了一些其他的架構(gòu),但是核心功能仍然是依托swoole擴(kuò)展實(shí)現(xiàn)的。
Server.php是全部的Swoole回調(diào)函數(shù)實(shí)現(xiàn)的類。
更多建議: