swoole學習之: 服務端(異步風格)-TCP/UDP服務器 - Swoole\Server的方法(三)

task()

投遞一個異步任務到task_worker池中。task()是非阻塞的, 執行完畢會立即返回。Worker進程可以繼續處理新的請求。使用Task功能,必須先設置task_worker_num,且必須設置ServeronTaskonFinish事件回調函數。

Swoole\Server->task(mixed $data, int $dstWorkerId=-1, callable $finishCallback): int
  • int $dstWorkerId
    • 指定要投遞給哪個Task進程, 傳入Task進程的ID即可, 範圍爲 [0, $server->setting['task_worker_num'] - 1]
    • 默認值-1表示隨機投遞, 底層會自動選擇一個空閒的Task進程
  • 返回值
    • 調用成功, 返回值爲整數的 task_id. 如果有finish回調, 則在onFinish中攜帶參數$task_id.
    • 調用失敗, 返回值爲 (bool)false, $task_id可能爲0
  • 提示
    • 此功能用於將慢速的任務異步地去執行, 比如一個聊天室服務器, 可以用它來發送廣播. 當任務完成時, 在task進程中調換用$server->finish('finish')告訴worker進程此任務已完成(也可以選Swoole\Server->finish).
$server->set([
    'worker_num' => 4,
    'task_worker_num' => 64, //啓動64個進程來接收異步任務
]);
$server->task($data, -1, function(Swoole\Server $server, $task_id, $data){
    echo 'Task callback:  task_id='.$task_id.PHP_EOL;
    var_dump($data);
});
  • $task_id是從0-42億的整數(unsigned int(4)????), 且在當前進程內是唯一的.
  • 默認不啓動task功能, 需要通過$server->set設置task_worker_num來啓動該功能.

注意:

  • task方法不能在task進程/用戶自定義進程中調用
  • 使用task必須爲Server設置onTaskonFinish回調事件, 否則$server->start()會失敗
  • task操作的次數必須小於onTask處理速度. 如果投遞容量超過處理能力,task數據會塞滿緩存區,導致Worker進程發生阻塞, Worker將無法接受新的請求
  • 在使用addProcess添加的用戶進程中無法使用task來投遞任務, 請使用sendMessage接口與Worker/Task進程通信

示例:

$server = new Swoole\Server('127.0.0.1', 9501, SWOOLE_BASE);
$server->set([
    'worker_num' => 2,
    'task_worker_num' => 4,//必須設置, 以啓動task模塊
]);
//注意: `BASE`模式下沒有`master`進程,因此不存在`onStart`事件
//$server->on('start', function($server){
//    echo 'Swoole Server started at '.date('Y-m-d H:i:s').PHP_EOL;
//});
$server->on('receive', function(Swoole\Server $server, $fd, $reactor_id, $data){
    $data = trim($data);
    echo '接收數據: '.$data.PHP_EOL;

    //啓動task任務1: 隨機投遞到空閒的Task進程
    $server->task($data.'== 隨機id', -1, function(Swoole\Server $server, $task_id, $data){
        //隨機分配的話, 回調函數中會收到參數 task_id
        echo 'Task RANDOM callback: task_id='.$task_id.', time: '.date('Y-m-d H:i:s').', msg: '.$data.PHP_EOL;
    });

    //啓動task任務2: 指定要投遞的Task進程的id
    $task_id = $server->task($data.' == 指定id', 0, function(Swoole\Server $server, $task_id, $data){
        echo 'Task ASSUMED ID callback: task_id='.$task_id.', time: '.date('Y-m-d H:i:s').', msg: '.$data.PHP_EOL;
    });
    //給客戶端發消息
    $server->send($fd, '分發任務, task_id='.$task_id.PHP_EOL);
});
//必須設置onTask和onFinish
//task收到任務
$server->on('task', function(Swoole\Server $server, $task_id, $reactor_id, $data){
    echo 'Task進程收到數據:'.date('Y-m-d H:i:s').PHP_EOL;
    echo '#'.$server->worker_id.', onTask: [pid='.$server->worker_pid.']: task_id='.$task_id.', data length: '. strlen($data).PHP_EOL;
    $server->finish($data);//執行完畢後通知Worker線程, 執行回調函數
});
//task異步任務完成
$server->on('finish', function(Swoole\Server $server, $task_id, $data){
    echo 'Task#'.$task_id.' finished, data length: '.strlen($data).PHP_EOL;
});

$server->on('workerStart', function($server, $worker_id){
    global $args;//可能爲null
    echo 'workerStart: worker_id='.$worker_id.PHP_EOL;
    //如果當前worker進程id大於等於設置的進程數量, 則設置進程名稱爲:
    $arg0 = isset($args[0]) ? $args[0] : '';
    if($worker_id >= $server->setting['worker_num']){
       swoole_set_process_name('php '.$arg0.': task_worker');
    }else{
       swoole_set_process_name('php '.$arg0.': _worker');
    }
});
$server->start();
//start => onWorkerStart => onReceive => task() => onTask => onFinish
//這裏的task有2次: 第一次是隨機id, 第二次是指定id

未完待續

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章