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