× 警告!旧版文档已经暂停维护,请查看新版文档。点击前往新版文档

Server->task

投递一个异步任务到task_worker池中。此函数是非阻塞的,执行完毕会立即返回。Worker进程可以继续处理新的请求。使用Task功能,必须先设置 task_worker_num,并且必须设置ServeronTaskonFinish事件回调函数。

int Server::task(mixed $data, int $dst_worker_id = -1) 
$task_id = $serv->task("some data");
//swoole-1.8.6或更高版本
$serv->task("taskcallback", -1, function (swoole_server $serv, $task_id, $data) {
    echo "Task Callback: ";
    var_dump($task_id, $data);
});

参数

  • $data要投递的任务数据,必须是可序列化的PHP变量
  • $dst_worker_id可以制定要给投递给哪个Task进程,传入ID即可,范围是0 - (serv->task_worker_num -1)

返回值

  • 调用成功,返回值为整数$task_id,表示此任务的ID。如果有finish回应,onFinish回调中会携带$task_id参数
  • 调用失败,返回值为false$task_id可能为0,因此必须使用===判断是否失败

说明

  • 未指定目标Task进程,调用task方法会判断Task进程的忙闲状态,底层只会向处于空闲状态的Task进程投递任务。如果所有Task进程均处于忙的状态,底层会轮询投递任务到各个进程。可以使用 server->stats 方法获取当前正在排队的任务数量。
  • 1.8.6版本增加了第三个参数,可以直接设置onFinish函数,如果任务设置了回调函数,Task返回结果时会直接执行指定的回调函数,不再执行Server的onFinish回调

$dst_worker_id1.6.11+后可用,默认为随机投递
$task_id是从0-42亿的整数,在当前进程内是唯一的
task方法不能在task进程/用户自定义进程中调用

此功能用于将慢速的任务异步地去执行,比如一个聊天室服务器,可以用它来进行发送广播。当任务完成时,在task进程中调用$serv->finish("finish")告诉worker进程此任务已完成。当然swoole_server->finish是可选的。

task底层使用Unix Socket管道通信,是全内存的,没有IO消耗。单进程读写性能可达100万/s,不同的进程使用不同的管道通信,可以最大化利用多核。

AsyncTask功能在1.6.4版本增加,默认不启动task功能,需要在手工设置task_worker_num来启动此功能
TaskWorker的数量在Server::set参数中调整,如task_worker_num => 64,表示启动64个进程来接收异步任务

配置参数

Server->task/taskwait/finish 3个方法当传入的$data数据超过8K时会启用临时文件来保存。当临时文件内容超过 server->package_max_length 时底层会抛出一个警告。此警告不影响数据的投递,过大的Task可能会存在性能问题。

WARN: task package is too big.

server->package_max_length 默认为2M

注意事项

  • 使用task必须为Server设置onTaskonFinish回调,否则Server->start会失败
  • task操作的次数必须小于onTask处理速度,如果投递容量超过处理能力,task数据会塞满缓存区,导致Worker进程发生阻塞。`Worker·进程将无法接收新的请求
  • 使用addProcess添加的用户进程中无法使用task投递任务,请使用sendMessage接口与Task工作进程通信

单向任务

MasterManagerUserProcess进程中投递的任务,是单向的。在TaskWorker进程中无法使用returnServer->finish()方法返回结果数据。

代码示例

$serv = new Swoole\Server("127.0.0.1", 9501, SWOOLE_BASE);

$serv->set(array(
    'worker_num' => 2,
    'task_worker_num' => 4,
));

$serv->on('Receive', function(Swoole\Server $serv, $fd, $from_id, $data) {
    echo "接收数据" . $data . "\n";
    $data = trim($data);
    $task_id = $serv->task($data, 0); 
    $serv->send($fd, "分发任务,任务id为$task_id\n");
});

$serv->on('Task', function (Swoole\Server $serv, $task_id, $from_id, $data) {
    echo "Tasker进程接收到数据";
    echo "#{$serv->worker_id}\tonTask: [PID={$serv->worker_pid}]: task_id=$task_id, data_len=".strlen($data).".".PHP_EOL;
    $serv->finish($data);
});

$serv->on('Finish', function (Swoole\Server $serv, $task_id, $data) {
    echo "Task#$task_id finished, data_len=".strlen($data).PHP_EOL;
});

$serv->on('workerStart', function($serv, $worker_id) {
    global $argv;
    if($worker_id >= $serv->setting['worker_num']) {
        swoole_set_process_name("php {$argv[0]}: task_worker");
    } else {
        swoole_set_process_name("php {$argv[0]}: worker");
    }
});

$serv->start();

  • 去也来来

    建议所有运算量大的timer都指派给task来异步执行。 第3个参数----->应该修改为:第2个参数

  • 小eye

    swoole_server->task返回的任务id 和 task worker id是两个不同的概念吧

  • 刘朱石强

    如何kill掉task进程?如何获得task的PID?

  • 刘朱石强

    个人觉得Task的设计上可以不要在$server->start()的时候马上创建好task进程,而应该是$server->task()时再动态创建进程,这样更符合应用场景。另外task数量由程序动态决定,可以随时生成或者kill task。如果是这样设计还可以有“多重onTask”。

  • 王钟凯

    Max_request 是否影响task任务的执行次数?

  • 程铭栋

    $server->on('task',function($serv,$task_id,$from_id, $data) 中参数$task_id请问如何清零? 当我的客户端断开了。再重连重新分配了fd,但是task_id还是继承了先前断开的任务数。

  • 天天

    $server->task()方法都可以在哪调用

  • 123

    谁说不能传递数组啊?

  • 2222

    可以为除资源类型之外的任意PHP变量

  • 冥王風

    用的cygwin 环境测试,在 on task中, $serv->connections 可以用count统计出数量,但是foreach却是空的,不知道啥情况了。。。

  • 韦元晓

    “AsyncTask功能在1.6.4版本增加,默认不启动task功能,需要在手工设置task_worker_num来启动此功能” ---- 这样的起名也是醉了啊。。。 AsyncTask Task task_worker ....都是一个东西,你起3个名字干什么

  • 老船长

    场景:websocket 版本:swoole-1.8.6 函数:$serv->task("taskcallback", -1, function (swoole_server $serv, $task_id, $data) { echo "Task Callback: "; var_dump($task_id, $data); }); 用这种方式回调,【有时连续接收时】会把系统搞死了,所有进程都停掉,但客户端的websocket也没断,但是发不出任何信息也收不到,此时在top里看到PHP进程占CPU90-100,但也不是总是这样。 然后刷新客户端尝试重新连接,连不上,握手没反应。

    原来用的是task》onTask》onFinish,没出现过这情况,看到1.8.6里有这种新方法,就全改成这样的了,毕竟这种方式,在写代码时要方便很多。

    另外,原来在onTask里处理的业务逻辑,都移到这里面的回调了,不知道和这有没有关系。

  • 屏风山下的猎人

    投递任务到task进程中,如果不指定task_worker_id是不是也是根据空闲状态来的

  • jimmy

    task可以设定一个自动回收时间吗

  • 周玮曦

    我$serv->task返回的task_id大于task_worker_num,我的swoole版本的问题还是文档描述有问题?

  • hanson

    @周玮曦 $serv->task返回的task_id和task_worker_num 是两回事呢

  • 傅雨

    客户端连接server后向task投递任务,在task执行的过程中如果客户端雨server的连接断了那task进程会继续执行么?

  • sky

    $serv->task("taskcallback", -1, function (swoole_server $serv, $task_id, $from_id,$data) { ... ... });

  • 建议task函数中加入onTask参数,当投递任务后调用此函数不再调用不再执行Server的onTask回调,第二个dst_worker_id参数传-1是不是代表不指定dst_worker_id自动指定,文档中并没有说明,希望改进。1.8.6版本增加了第三个参数说明建议加在前两个参数说明之后,这样说明顺序就统一成了参数说明 、返回说明 、注意事项。建议参考PHP手册文档说明方式,更有条理性。

  • AN棒棒糖

    task 进程中为什么不支持异步task任务的投递了?

  • Vijay

    实测,在task方法里传入回调函数,依然会执行服务器的onFinish回调

  • 傲雪孤魂

    @Vijay

    实测,在task方法里传入回调函数,依然会执行服务器的onFinish回调

    实测,swoole 4.0.0, 在task方法里传入回调函数,并不会执行onFinish 的回调

  • 蛟十五

    swoole_set_process_name不支持macos????

  • 新用户(手机注册)

    @乌蒙岛蛟十五 如你所见

  • S
    S

    task任务,能增加任务超时功能就好了,把超时的任务清理了, 不然死循环也在一直做任务

  • zouyuanbin

    Swoole\Server\Port::on(): unknown event types[task] swoole版本是4.2.1的,

  • 新用户(手机注册)

    我16核系统32g内存 设置了3000个task,客户端短链接 基本上连接三千次左右就不继续做任务了

  • 13262732358

    $this->server->task("haha", -1, function ($server, $task_id, $data) {}) 后边的回调函数无效为啥呢。只能触发onTask函数