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

未完待续

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