# 协程池
首先要声明的一点是,协程池这个概念是我自己编的。
因为协程的特点,它是单线程下运行的,所以在一个进程内同时实际上只会有一个协程的代码在执行逻辑,但是后面的 IO 操作、协程挂起等待的操作都是同时去做的,比如数据库的大数据读取、写入需要耗时几秒甚至几十秒,这时用基于协程的 MySQL 连接池就完全不是问题。
但是就拿 MySQL 举例,我们 MySQL 使用的是 TCP 连接,而无论是 MySQL 还是 TCP 连接,最大数量都是有限的。我们即使设置了允许最大协程数量非常大,比如上百万,但是也不能让数据库连接池一个池支持上百万的连接。
这时假设高并发进来了怎么办呢?这时就需要框架提出的一个折中方案:协程池了。
顾名思义,协程池是一个容纳协程的区域,而协程里又容纳着各种各样需要阻塞调用被协程调用的 IO 操作,协程池用作限制协程的数量。
use ZM\Utils\CoroutinePool;
use ZM\DB\DB;
// 传统写法,一旦高并发则可能导致 Too many connections
go(funuction(){
DB::rawQuery("INSERT INTO users VALUES(?,?)", ["admin", "password"]);
});
// 协程池写法
CoroutinePool::go(function(){
DB::rawQuery("INSERT INTO users VALUES(?,?)", ["admin", "password"]);
}, "foo");
2
3
4
5
6
7
8
9
10
11
参数:go(callable $func, $name = "default")
$name
为协程池对应的名字,你可以设置多个协程池,用来支持不同的需要限制并发 IO 数量的地方,例如 Redis 和 MySQL 设置不同的名字。$func
可为闭包或可调用的方法名称或数组。
# 配置
默认情况下,直接调用 CoroutinePool::go()
时,协程池大小为 30,也就是如果有 30 个协程进入了挂起状态(比如数据库在执行查询语句),那么更多的协程执行时就会阻塞并以协程等待的方式等待,直到现有的 30 个协程中的一部分完成了它的工作。
# 方法
# CoroutinePool::go()
将协程放入协程池运行。
如果不写 $name
参数,则使用的是默认协程池。
# CoroutinePool::defaultSize()
设置默认协程池的大小(默认 30)
CoroutinePool::defaultSize(64);
for($i = 0; $i < 1000; ++$i) {
CoroutinePool::go(function(){
DB::rawQuery("SELECT * FROM users");
});
}
2
3
4
5
6
# CoroutinePool::setSize()
定义:setSize($name, int $size)
$name
为字符串,是你要用的协程池的名称。
$size
为大小,最大不可超过 Swoole 配置文件中指定的最大协程数量。