Swoole 基础入门记录
Swoole 支持 TCP、UDP、WebSocket、HTTP 等服务器。创建服务 $server 后,可通过 $server->on() 绑定事件。以 TCP 服务器为例,在 Arch Linux 环境下,运行以下程序 test.php。
#!/usr/bin/php
<?php
Swoole\Runtime::enableCoroutine(true);
echo posix_getpid() . PHP_EOL;
$server = new swoole_server('127.0.0.1', 8080);
$server->on('connect', function ($server, $fd) {
echo posix_getpid() . PHP_EOL;
echo "open: $fd" . PHP_EOL;
});
$server->on('receive', function ($server, $fd, $reactor_id, $data) {
echo posix_getpid() . PHP_EOL;
if (!empty($data)) {
sleep(5); // 模拟处理任务
$server->send($fd, "data: $data");
} else {
$server->close($fd);
}
});
$server->on('close', function ($server, $fd) {
echo "close: {$fd}" . PHP_EOL;
});
$server->start();
查看 htop,搜索相关进程和线程,内容如下(绿色部分为线程)。

执行
$ nc 127.0.0.1:8080
同一 $fd 输出的 pid 相同,先后发送两次数据,等待一次的响应时间后即能先后得到返回数据。
由于 Swoole 新版本增加了对 sleep() 的 hook,因此此处相当于调用 Coroutine::sleep(),通过协程调度器实现,对当前协程 yield 让出时间片,在定时结束后恢复运行。
若去掉首行的 Swoole\Runtime::enableCoroutine(true),原生的 sleep() 会使用系统调用阻塞整个进程,先后发送两个数据后,需要等待两次响应时间。阻塞针对整个进程,而非针对单个的协程。
Swoole 现在使用 go、defer、chan 等 Go 语言中关键字的形式提供类似的协程模式。使用 go() 启动一个协程,协程间通过生产者消费者队列 chan() 通信,在 function 退出前根据 LIFO 的顺序执行 defer() 任务。 示例如下。
#!/usr/bin/php
<?php
$c = new chan(10);
for ($i = 0; $i < 10; $i++) {
@go (function () use ($i, $c) {
@defer (function () use ($c) {
$rand = rand(0, 100);
$c->push($rand);
echo " Push: $rand" . PHP_EOL;
});
echo '$i';
});
}
echo PHP_EOL;
for ($i = 0; $i < 10; $i++) {
echo 'Pop: ' . $c->pop() . PHP_EOL;
}
输出的结果为
0 Push: 60
1 Push: 1
2 Push: 83
3 Push: 97
4 Push: 81
5 Push: 70
6 Push: 91
7 Push: 6
8 Push: 8
9 Push: 32Pop: 60
Pop: 1
Pop: 83
Pop: 97
Pop: 81
Pop: 70
Pop: 91
Pop: 6
Pop: 8
Pop: 32