# 协程池

首先要声明的一点是,协程池这个概念是我自己编的。

因为协程的特点,它是单线程下运行的,所以在一个进程内同时实际上只会有一个协程的代码在执行逻辑,但是后面的 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");
1
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");
    });
}
1
2
3
4
5
6

# CoroutinePool::setSize()

定义:setSize($name, int $size)

$name 为字符串,是你要用的协程池的名称。

$size 为大小,最大不可超过 Swoole 配置文件中指定的最大协程数量。

上次更新: 10/17/2021, 3:37:55 PM