三十四、Swoole 基础学习笔记 - Swoole Channel 协程间通信
hi,我是温新,一名PHPer
文章基于 Swoole 5.0.1 版本编写。
学习目标:了解协程间通信
说明:本篇文章结合官方文档编写及参考网络资料编写,虽非全部原创,但也是结合了自己的理解,若转载请附带本文 URL,编写不易,持续编写更不易,谢谢!
通道,用于协程间通讯,支持多生产者协程和多消费者协程。底层自动实现了协程的切换和调度。
什么是 Channel
Channel
可以理解为消息队列,只不过是协程间的消息队列,多个协程通过 push
和 pop
操作队列中的生产消息和消费消息,用来发送或者接收数据进行协程之间的通讯。需要注意的是 Channel
是没法跨进程的,只能一个 Swoole
进程里的协程间通讯,最典型的应用是连接池和并发调用。
实现原理
- 通道与
PHP
的Array
类似,仅占用内存,没有其他额外的资源申请,所有操作均为内存操作,无IO
消耗 - 底层使用
PHP
引用计数实现,无内存拷贝。即使是传递巨大字符串或数组也不会产生额外性能消耗 -
channel
基于引用计数实现,是零拷贝的
通信案例
Swoole\Coroutine\run(function () {
// 实例化通道
$channel = new Swoole\Coroutine\Channel(1);
// 这个协程负责向通道中写入数据
Swoole\Coroutine::create(function() use ($channel) {
for ($i = 0; $i < 10; $i++) {
Swoole\Coroutine::sleep(1);
// 通道中写入数据
$channel->push([
'rand' => rand(1000, 9999),
'index' => $i,
]);
echo $i . PHP_EOL;
}
});
// 这个协程负责从通道中读取数据
Swoole\Coroutine::create(function () use ($channel) {
while (true) {
$data = $channel->pop(2);
if ($data) {
print_r($data);
} else {
assert($channel->errCode === SWOOLE_CHANNEL_TIMEOUT);
break;
}
}
});
});
API 学习
__construct
含义:通道构造方法。
语法:
Swoole\Coroutine\Channel::__construct(int $capacity = 1)
# 参数
$capacity:设置容量 【必须为大于或等于 1 的整数】
底层使用 PHP 引用计数来保存变量,缓存区只需要占用
$capacity * sizeof(zval)
字节的内存,PHP7
版本下zval
为16
字节,如$capacity = 1024
时,Channel
最大将占用16K
内存
push
含义:向通道中写入数据。
语法:
Swoole\Coroutine\Channel->push(mixed $data, float $timeout = -1): bool
# 参数
$data:push 数据 【可以是任意类型的 PHP 变量,包括匿名函数和资源】;
$timeout:超时时间。
在通道已满的情况下,
push
会挂起当前协程,在约定的时间内,如果没有任何消费者消费数据,将发生超时,底层会恢复当前协程,push
调用立即返回false
,写入失败
扩展:
通道已满:
1、自动
yield
当前协程,其他消费者协程pop
消费数据后,通道可写,将重新resume
当前协程; 2、多个生产者协程同时
push
时,底层自动进行排队,底层会按照顺序逐个resume
这些生产者协程。通道为空:
1、自动唤醒其中一个消费者协程;
2、多个消费者协程同时
pop
时,底层自动进行排队,按照顺序逐个resume
这些消费者协程。
pop
含义:从通道中读取数据。
语法:Swoole\Coroutine\Channel->pop(float $timeout = -1): mixed
扩展
通道已满
1、
pop
消费数据后,将自动唤醒其中一个生产者协程,让其写入新数据; 2、多个生产者协程同时
push
时,底层自动进行排队,按照顺序逐个resume
这些生产者协程。通道为空
1、自动
yield
当前协程,其他生产者协程push
生产数据后,通道可读,将重新resume
当前协程; 2、多个消费者协程同时
pop
时,底层自动进行排队,底层会按照顺序逐个resume
这些消费者协程。
stats
含义:获取通道的状态。
语法:Swoole\Coroutine\Channel->stats(): array
返回值:
- 返回一个数组,缓冲通道将包括
4
项信息,无缓冲通道返回2
项信息-
consumer_num
消费者数量,表示当前通道为空,有N
个协程正在等待其他协程调用push
方法生产数据 -
producer_num
生产者数量,表示当前通道已满,有N
个协程正在等待其他协程调用pop
方法消费数据 -
queue_num
通道中的元素数量
-
close
含义:关闭通道。并唤醒所有等待读写的协程。
语法:Swoole\Coroutine\Channel->close(): bool
length
含义:获取通道中的元素数量。
语法:Swoole\Coroutine\Channel->length(): int
isEmpty
含义:判断当前通道是否为空。
语法:Swoole\Coroutine\Channel->isEmpty(): bool
isFUll
含义:判断当前通道是否已满。
语法:Swoole\Coroutine\Channel->isFull(): bool
我是温新,本篇文章结束。