diff --git a/public/zh-cn/_sidebar.md b/public/zh-cn/_sidebar.md index a58552a..7c5d402 100644 --- a/public/zh-cn/_sidebar.md +++ b/public/zh-cn/_sidebar.md @@ -9,7 +9,7 @@ * [HTTP服务器](start/start_http_server.md) * [WebSocket服务器](start/start_ws_server.md) * [MQTT(物联网)服务器](start/start_mqtt.md) - * [执行异步任务(Task)](start/start_task.md) + * [执行异步任务](start/start_task.md) * [协程初探](start/coroutine.md) * [服务端(异步风格)](server/init.md) @@ -41,46 +41,45 @@ * [MySQL客户端](coroutine_client/mysql.md) * [Redis客户端](coroutine_client/redis.md) +* 进程管理 (Process) + * [创建进程](process/process.md) + * [进程池](process/process_pool.md) + * [进程管理器](process/process_manager.md) + +* 线程管理 (Thread) + * [创建线程](thread/thread.md) + * [线程池](thread/pool.md) + * [方法与属性](thread/info) + * [并发Map](thread/map.md) + * [并发List](thread/arraylist.md) + * [并发Queue](thread/queue.md) + * [数据类型](thread/transfer.md) + * [协程 (Coroutine)](coroutine.md) * [一键协程化](runtime.md) - * [核心API](coroutine/coroutine.md) - * [协程容器](coroutine/scheduler.md) + * [协程容器](coroutine/scheduler.md) + * [协程API](coroutine/coroutine.md) * [系统API](coroutine/system.md) - * [进程API](coroutine/proc_open.md) - * [Channel](coroutine/channel.md) - * [WaitGroup](coroutine/wait_group.md) - * [Barrier](coroutine/barrier.md) * [并发调用](coroutine/multi_call.md) * [连接池](coroutine/conn_pool.md) * [Library](library.md) * [调试协程](coroutine/gdb.md) * [编程须知](coroutine/notice.md) +* 进程/线程/协程同步 + * [锁](memory/lock.md) + * [原子计数](memory/atomic.md) + * [同步屏障](thread/barrier.md) + * [高性能共享内存](memory/table.md) + * [Channel](coroutine/channel.md) + * [WaitGroup](coroutine/wait_group.md) + * 文件异步操作 * [实现](file/engine.md) * [配置](file/setting.md) -* 线程管理 (Thread) - * [创建线程](thread/thread.md) - * [线程池(Thread\Pool)](thread/pool.md) - * [方法与属性](thread/info) - * [并发Map](thread/map.md) - * [并发List](thread/arraylist.md) - * [并发Queue](thread/queue.md) - * [同步屏障Barrier](thread/barrier.md) - * [数据类型](thread/transfer.md) - -* 进程管理 (Process) - * [创建进程](process/process.md) - * [进程池(Process\Pool)](process/process_pool.md) - * [进程管理器(Process\Manager)](process/process_manager.md) - * [高性能共享内存(Table)](memory/table.md) - -* 并发管理 - * [锁(Lock)](memory/lock.md) - * [原子计数(Atomic)](memory/atomic.md) - * [事件循环(EventLoop)](event.md) - * [定时器(Timer)](timer.md) +* [事件循环(EventLoop)](event.md) +* [定时器(Timer)](timer.md) * 其他 * [常量](consts.md) diff --git a/public/zh-cn/coroutine/barrier.md b/public/zh-cn/coroutine/barrier.md index 27fa7a2..72621b3 100644 --- a/public/zh-cn/coroutine/barrier.md +++ b/public/zh-cn/coroutine/barrier.md @@ -1,4 +1,4 @@ -# Coroutine\Barrier +# 协程同步执行屏障 Barrier 在 [Swoole Library](https://github.com/swoole/library) 中底层提供了一个更便捷的协程并发管理工具:`Coroutine\Barrier` 协程屏障,或者叫协程栅栏。基于 `PHP` 引用计数和 `Coroutine API` 实现。 @@ -6,6 +6,8 @@ !> Swoole 版本 >= v4.5.5 时可用。 +!> 该协程屏障只能用于单进程或者单线程中的多协程同步,主要作用还是让主协程等待全部子协程完成任务后再退出。 + ## 使用示例 ```php @@ -33,6 +35,32 @@ run(function () { }); ``` +## 方法 + +### make() +生成一个协程屏障。 + +```php +Coroutine\Barrier::make(): self +``` + +### wait() +在所有协程还未完成任务时,主协程在该函数等待所有协程完成任务。 + +```php +Coroutine\Barrier::wait(Barrier &$barrier, float $timeout = -1): void +``` + +* **参数** + * `int $barrier` + * 功能:由`Coroutine\Barrier::make()`返回的协程屏障。 + * 默认值:无。 + * 其它值:无。 + * `float $timeout` + * 功能:超时时间。 + * 默认值:-1,表示永不超时。 + * 其它值:无。 + ## 执行流程 * 先使用`Barrier::make()`创建了一个新的协程屏障 diff --git a/public/zh-cn/coroutine/channel.md b/public/zh-cn/coroutine/channel.md index 2e0394e..ee97631 100644 --- a/public/zh-cn/coroutine/channel.md +++ b/public/zh-cn/coroutine/channel.md @@ -1,4 +1,4 @@ -# Coroutine\Channel +# Channel > 建议先查看[概览](/coroutine),了解一些协程基本概念后再看此节。 diff --git a/public/zh-cn/coroutine/coroutine.md b/public/zh-cn/coroutine/coroutine.md index 4966394..ee89848 100644 --- a/public/zh-cn/coroutine/coroutine.md +++ b/public/zh-cn/coroutine/coroutine.md @@ -569,6 +569,8 @@ Swoole\Coroutine::getElapsed([$cid]): int !> Swoole版本 >= `v4.7.0` 可用 +!> 你无法取消正在进行文件IO的协程,因为此时内核正在进行文件读写操作,如果此时取消协程,会导致内核正在操作的内存被释放导致段错误。 + ```php Swoole\Coroutine::cancel($cid): bool ``` diff --git a/public/zh-cn/coroutine/notice.md b/public/zh-cn/coroutine/notice.md index 4a98e0c..a141a9b 100644 --- a/public/zh-cn/coroutine/notice.md +++ b/public/zh-cn/coroutine/notice.md @@ -14,6 +14,13 @@ !> `hook`这两个入口函数后,大部分情况下会把平坦的PHP指令调用变为`C`函数调用,增加C栈的消耗。 +## 协程中创建进程 + +由于在协程空间内`fork`进程会带着其他协程上下文,因此底层禁止了在`Coroutine`中使用`Process`模块。可以使用 + +* `System::exec()`或`Runtime Hook`+`shell_exec`实现外面程序运行 +* `Runtime Hook`+`proc_open`实现父子进程交互通信 + ## 退出协程 在Swoole低版本中,协程中使用`exit`强行退出脚本会导致内存错误导致不可预期的结果或`coredump`,在Swoole服务中使用`exit`会使整个服务进程退出且内部的协程全部异常终止导致严重问题,Swoole长期以来一直禁止开发者使用`exit`,但开发者可以使用抛出异常这种非常规的方式,在顶层`catch`来实现和`exit`相同的退出逻辑 diff --git a/public/zh-cn/coroutine/scheduler.md b/public/zh-cn/coroutine/scheduler.md index b62bdeb..354bfd9 100644 --- a/public/zh-cn/coroutine/scheduler.md +++ b/public/zh-cn/coroutine/scheduler.md @@ -1,65 +1,29 @@ -# Coroutine\Scheduler - -?> 所有的[协程](/coroutine)必须在`协程容器`里面[创建](/coroutine/coroutine?id=create),`Swoole`程序启动的时候大部分情况会自动创建`协程容器`,用`Swoole`启动程序的方式一共有三种: +# 协程容器 +所有的[协程](/coroutine)必须在`协程容器`里面[创建](/coroutine/coroutine?id=create),`Swoole`程序启动的时候大部分情况会自动创建`协程容器`,用`Swoole`启动程序的方式一共有三种: - 调用[异步风格](/server/init)服务端程序的[start](/server/methods?id=start)方法,此种启动方式会在事件回调中创建`协程容器`,参考[enable_coroutine](/server/setting?id=enable_coroutine)。 - 调用`Swoole`提供的2个进程管理模块[Process](/process/process)和[Process\Pool](/process/process_pool)的[start](/process/process_pool?id=start)方法,此种启动方式会在进程启动的时候创建`协程容器`,参考这两个模块构造函数的`enable_coroutine`参数。 - - 其他直接裸写协程的方式启动程序,需要先创建一个协程容器(`Coroutine\run()`函数,可以理解为java、c的`main`函数),例如: - -* **启动一个全协程`HTTP`服务** - -```php -use Swoole\Coroutine\Http\Server; -use function Swoole\Coroutine\run; - -run(function () { - $server = new Server('127.0.0.1', 9502, false); - $server->handle('/', function ($request, $response) { - $response->end("

Index

"); - }); - $server->handle('/test', function ($request, $response) { - $response->end("

Test

"); - }); - $server->handle('/stop', function ($request, $response) use ($server) { - $response->end("

Stop

"); - $server->shutdown(); - }); - $server->start(); -}); -echo 1;//得不到执行 -``` + - 其他直接裸写协程的方式启动程序,需要先创建一个协程容器`Coroutine\Scheduler`(可以理解为java、c的`main`函数),协程容器会初始化完毕运行协程所需的环境。 -* **添加2个协程并发的做一些事情** +!> 在`Swoole v4.4+`版本可用。 +## 使用示例 ```php -use Swoole\Coroutine; -use function Swoole\Coroutine\run; - -run(function () { - Coroutine::create(function() { - var_dump(file_get_contents("http://www.xinhuanet.com/")); - }); +use Swoole\Coroutine\Scheduler; - Coroutine::create(function() { - Coroutine::sleep(1); - echo "done\n"; - }); +$scheduler = new Scheduler(); +$scheduler->set(['hook_flags' => SWOOLE_HOOK_ALL]); +$scheduler->add(function() { + sleep(1); }); -echo 1;//可以得到执行 +return $scheduler->start(); ``` -!> 在`Swoole v4.4+`版本可用。 - -!> 不可以嵌套`Coroutine\run()`。 -`Coroutine\run()`里面的逻辑如果有未处理的事件在`Coroutine\run()`之后就进行[EventLoop](learn?id=什么是eventloop),后面的代码将得不到执行,反之,如果没有事件了将继续向下执行,可以再次`Coroutine\run()`。 - -上文的`Coroutine\run()`函数其实是对`Swoole\Coroutine\Scheduler`类(协程调度器类)的封装,想了解细节的同学可以看`Swoole\Coroutine\Scheduler`的方法: +## 方法 ### set() -?> **设置协程运行时参数。** - -?> 是`Coroutine::set`方法的别名。请参考 [Coroutine::set](/coroutine/coroutine?id=set) 文档 +?> **设置协程运行时参数。** ,是`Coroutine::set`方法的别名。请参考 [Coroutine::set](/coroutine/coroutine?id=set) 文档。 ```php Swoole\Coroutine\Scheduler->set(array $options): bool @@ -74,9 +38,7 @@ $sch->set(['max_coroutine' => 100]); ### getOptions() -?> **获取设置的协程运行时参数。** Swoole版本 >= `v4.6.0` 可用 - -?> 是`Coroutine::getOptions`方法的别名。请参考 [Coroutine::getOptions](/coroutine/coroutine?id=getoptions) 文档 +?> **获取设置的协程运行时参数。** Swoole版本 >= `v4.6.0` 可用,是`Coroutine::getOptions`方法的别名。请参考 [Coroutine::getOptions](/coroutine/coroutine?id=getoptions) 文档。 ```php Swoole\Coroutine\Scheduler->getOptions(): null|array @@ -177,4 +139,58 @@ Swoole\Coroutine\Scheduler->start(): bool * **返回值** * 启动成功,会执行所有添加的任务,所有协程退出时`start`会返回`true` - * 启动失败返回`false`,原因可能是已经启动了或者已经创建了其他调度器无法再次创建 \ No newline at end of file + * 启动失败返回`false`,原因可能是已经启动了或者已经创建了其他调度器无法再次创建 + + +## 简化函数 +为了简化创建协程容器的步骤,`Swoole`封装了一个`Coroutine\run()`函数。 + +### 使用示例 +* **启动一个全协程`HTTP`服务** + +```php +use Swoole\Coroutine\Http\Server; +use function Swoole\Coroutine\run; + +run(function () { + $server = new Server('127.0.0.1', 9502, false); + $server->handle('/', function ($request, $response) { + $response->end("

Index

"); + }); + $server->handle('/test', function ($request, $response) { + $response->end("

Test

"); + }); + $server->handle('/stop', function ($request, $response) use ($server) { + $response->end("

Stop

"); + $server->shutdown(); + }); + $server->start(); +}); +echo 1;//得不到执行 +``` + +* **添加2个协程并发的做一些事情** + +```php +use Swoole\Coroutine; +use function Swoole\Coroutine\run; + +run(function () { + Coroutine::create(function() { + var_dump(file_get_contents("http://www.xinhuanet.com/")); + }); + + Coroutine::create(function() { + Coroutine::sleep(1); + echo "done\n"; + }); +}); +echo 1;//可以得到执行 +``` + +!> 使用`Coroutine\run()`函数需要确保`swoole.enable_library=On`(默认为On),因为该函数是通过`library`提供的。 + +!> 使用协程容器会默认设置一键协程化,使所有的PHP阻塞操作变成非阻塞操作。 + +!> 不可以嵌套`Coroutine\run()`。`Coroutine\run()`里面的逻辑如果有未处理的事件在`Coroutine\run()`之后就进行[EventLoop](learn?id=什么是eventloop),后面的代码将得不到执行,反之,如果没有事件了将继续向下执行,可以再次`Coroutine\run()`。 + diff --git a/public/zh-cn/coroutine/wait_group.md b/public/zh-cn/coroutine/wait_group.md index 8bba6bb..9fc8c04 100644 --- a/public/zh-cn/coroutine/wait_group.md +++ b/public/zh-cn/coroutine/wait_group.md @@ -2,14 +2,7 @@ 在`Swoole4`中可以使用[Channel](/coroutine/channel)实现协程间的通信、依赖管理、协程同步。基于[Channel](/coroutine/channel)可以很容易地实现`Golang`的`sync.WaitGroup`功能。 -## 实现代码 - -> 此功能是使用PHP编写的功能,并不是C/C++代码,实现源代码在 [Library](https://github.com/swoole/library/blob/master/src/core/Coroutine/WaitGroup.php) 当中 - -* `add`方法增加计数 -* `done`表示任务已完成 -* `wait`等待所有任务完成恢复当前协程的执行 -* `WaitGroup`对象可以复用,`add`、`done`、`wait`之后可以再次使用 +!> `WaitGroup`只能用于单进程或者单线程中的多协程同步,主要作用还是让主协程等待全部子协程完成任务。 ## 使用示例 @@ -69,4 +62,34 @@ run(function () { //这里 $result 包含了 2 个任务执行结果 var_dump($result); }); -``` \ No newline at end of file +``` + +## 方法 + +### __construct +`WaitGroup`的构造函数。 + +```php +Swoole\Coroutine\WaitGroup->__construct() +``` + +### add +在子协程中使用,表示引用计数加1。 + +```php +Swoole\Coroutine\WaitGroup->add(): void +``` + +### done +在子协程中使用,表示任务已完成,引用计数减一。 + +```php +Swoole\Coroutine\WaitGroup->done(): void +``` + +### wait +在主协程中使用,主协程会等待子协程全部任务完成之后再退出。 + +```php +Swoole\Coroutine\WaitGroup->wait(): void +``` diff --git a/public/zh-cn/environment.md b/public/zh-cn/environment.md index ded165d..89911bb 100644 --- a/public/zh-cn/environment.md +++ b/public/zh-cn/environment.md @@ -85,6 +85,20 @@ pecl install -D 'enable-sockets="no" enable-openssl="yes" enable-http2="yes" ena pecl install --configureoptions 'enable-sockets="no" enable-openssl="yes" enable-http2="yes" enable-mysqlnd="yes" enable-swoole-json="no" enable-swoole-curl="yes" enable-cares="yes"' swoole ``` +## PIE + +Swoole 项目支持由 PHP 全新的扩展安装工具 PIE 一键下载安装。 + +```shell +pie install swoole/swoole:5.1.5 +``` + +通过 PIE 安装 Swoole 时,在安装过程中它会询问是否要启用某些功能,这也可以在运行安装之前提供,例如: + +```shell +pie install swoole/swoole:5.1.5 --enable-socket --enable-swoole-curl +``` + ## 添加Swoole到php.ini 最后,编译安装成功后,修改`php.ini`加入 @@ -225,6 +239,14 @@ with-swoole-odbc="unixODBC,/usr" >`v6.0`版本后可用,而且需要安装`liburing`依赖来支持此特性,如果磁盘性能够好的情况下两种模式性能相差不大,只有`I/O`压力较大的情况下,`iouring`模式性能会优于异步线程模式。 +>`io_uring`对linux内核版本要求较高,建议在linux 5.12+,liburing 2.6+ 以上的系统使用。 + +#### --enable-zstd + +添加这个编译选项后,`http`服务端和客户端之间可以使用高性能压缩工具`Zstd`压缩响应。 + +>`v6.0`版本后可用,而且需要安装`libzstd`依赖来支持此特性。 + ### 特殊参数 !> **如无历史原因不建议启用** diff --git a/public/zh-cn/event.md b/public/zh-cn/event.md index 65a28f7..a53c04a 100644 --- a/public/zh-cn/event.md +++ b/public/zh-cn/event.md @@ -1,6 +1,6 @@ # Event -`Swoole`扩展还提供了直接操作底层`epoll/kqueue`事件循环的接口。可将其他扩展创建的`socket`,`PHP`代码中`stream/socket`扩展创建的`socket`等加入到`Swoole`的[EventLoop](/learn?id=什么是eventloop)中, +`Swoole`扩展还提供了直接操作底层`epoll/kqueue/poll/select`事件循环的接口。可将其他扩展创建的`socket`,`PHP`代码中`stream/socket`扩展创建的`socket`等加入到`Swoole`的[EventLoop](/learn?id=什么是eventloop)中, 否则第三方的$fd如果是同步IO会导致Swoole的EventLoop得不到执行,[参考案例](/learn?id=同步io转换成异步io)。 !> `Event`模块比较底层,是`epoll`的初级封装,使用者最好有IO多路复用编程经验。 @@ -41,9 +41,9 @@ Swoole\Event::add(mixed $sock, callable $read_callback, callable $write_callback * **其它值**:无 * **`int $flags`** - * **功能**:事件类型的掩码【可选择关闭/开启可读可写事件,如`SWOOLE_EVENT_READ`、`SWOOLE_EVENT_WRITE`或者`SWOOLE_EVENT_READ|SWOOLE_EVENT_WRITE`】 + * **功能**:事件类型的掩码 * **默认值**:无 - * **其它值**:无 + * **其它值**:`SWOOLE_EVENT_READ`监听可读事件,`SWOOLE_EVENT_WRITE`监听可写事件,`SWOOLE_EVENT_READ|SWOOLE_EVENT_WRITE`同时监听可读可写事件 * **$sock 4种类型** @@ -58,7 +58,7 @@ object | `Swoole\Process`或`Swoole\Client`,底层自动转换为[UnixSocket]( * 添加事件监听成功成功返回`true` * 添加失败返回`false`,请使用`swoole_last_error`获取错误码 - * 已添加过的`socket`不能重复添加,可以使用`swoole_event_set`修改`socket`对应的回调函数和事件类型 + * 已添加过的`socket`不能重复添加,重复添加同一个`socket`会抛出错误。可以使用`swoole_event_set`修改`socket`对应的回调函数和事件类型 !> 使用`Swoole\Event::add`将`socket`加入到事件监听后,底层会自动将该`socket`设置为非阻塞模式 @@ -95,9 +95,10 @@ Swoole\Event::set($fd, mixed $read_callback, mixed $write_callback, int $flags): * **参数** * 参数与[Event::add](/event?id=add)完全相同。如果传入`$fd`在[EventLoop](/learn?id=什么是eventloop)中不存在返回`false`。 - * 当`$read_callback`不为`null`时,将修改可读事件回调函数为指定的函数 - * 当`$write_callback`不为`null`时,将修改可写事件回调函数为指定的函数 - * `$flags`可关闭/开启,可写(`SWOOLE_EVENT_READ`)和可读(`SWOOLE_EVENT_WRITE`)事件的监听 + * 当`$read_callback`不为`null`时,将修改可读事件回调函数为指定的函数。 + * 当`$write_callback`不为`null`时,将修改可写事件回调函数为指定的函数。 + * 如果`$flags`为`SWOOLE_EVENT_READ`,意味着只监听可读事件,停止监听可写事件。 + * 如果`$flags`为`SWOOLE_EVENT_WRITE`,意味着只监听可写事件,停止监听可读事件。 !> 注意如果监听了`SWOOLE_EVENT_READ`事件,而当前并未设置`read_callback`,底层会直接返回`false`,添加失败。`SWOOLE_EVENT_WRITE`同理。 @@ -198,9 +199,9 @@ Event::add($fp, function($fp) { Event::write($fp, $data); ``` -#### SOCKET缓存区已满后,Swoole的底层逻辑 +#### socket缓存区已满后,Swoole的底层逻辑 -持续写入`SOCKET`如果对端读取不够快,那`SOCKET`缓存区会塞满。`Swoole`底层会将数据存到内存缓存区中,直到可写事件触发再写入`SOCKET`。 +持续写入`socket`如果对端读取不够快,那`socket`缓存区会塞满。`Swoole`底层会将数据存到内存缓存区中,直到可写事件触发再写入`socket`。 如果内存缓存区也被写满了,此时`Swoole`底层会抛出`pipe buffer overflow, reactor will block.`错误,并进入阻塞等待。 diff --git a/public/zh-cn/file/engine.md b/public/zh-cn/file/engine.md index 1ffb740..bc3394c 100644 --- a/public/zh-cn/file/engine.md +++ b/public/zh-cn/file/engine.md @@ -1,4 +1,4 @@ -# 异步文件操作 +# 文件异步操作 `Swoole`的[一键协程化](/runtime)可以很方便的将`PHP`的文件操作由同步阻塞变为异步执行,`Swoole`一共内置了两种不同的文件异步策略。 @@ -13,13 +13,12 @@ * `io_uring`是`Swoole v6.0`之后内置的策略,基于`io_uring`和`epoll`实现异步。 * 吞吐量高,可以处理大量文件异步操作。 -* 对`linux`版本有要求,也需要依赖`liburing`这个共享库,有些操作系统没法使用这个特性。 -* 由于是基于`文件描述符`实现文件异步,只支持少数`PHP`的文件操作函数。 -* 对linux内核版本要求较高。 +* `io_uring`对linux内核版本要求较高,建议在linux 5.12+,liburing 2.6+ 以上的系统使用,有些操作系统没法使用这个特性。 +* 由于是基于`文件描述符`实现文件异步,只支持一些`PHP`的文件操作函数。 !> 当系统安装了`liburing`和编译`Swoole`开启了`--enable-iouring`之后才能使用。 !> 开启了`io_uring`之后并不会替换掉`线程池`模式,有些`io_uring`没法协程化的函数还是会让`线程池`处理。 -!> `io_uring`只能处理`file_get_contents`,`file_put_contents`,`fopen`,`fclose`,`fread`,`fwrite`,`mkdir`,`unlink`,`fsync`,`fdatasync`,`rename`,`fstat`,`lstat`,`filesize`函数。 +!> `io_uring`只能协程化`file_get_contents`,`file_put_contents`,`fopen`,`fclose`,`fread`,`fwrite`,`mkdir`,`unlink`,`fsync`,`fdatasync`,`rename`,`fstat`,`lstat`,`filesize`函数。 diff --git a/public/zh-cn/file/setting.md b/public/zh-cn/file/setting.md index db31adc..6171de8 100644 --- a/public/zh-cn/file/setting.md +++ b/public/zh-cn/file/setting.md @@ -7,20 +7,22 @@ ```php 10, 'aio_worker_num' => 20, 'aio_max_wait_time' => 60, 'aio_max_idle_time' => 60, - 'iouring_entries' => 1024 + 'iouring_entries' => 1024, + 'iouring_workers' => 16, + 'iouring_flag' => SWOOLE_IOURING_SQPOLL ]); $server = new Swoole\Server('127.0.0.1', 9501); $server->set([ - 'aio_core_worker_num' => 10, 'aio_worker_num' => 20, 'aio_max_wait_time' => 60, 'aio_max_idle_time' => 60, - 'iouring_entries' => 1024 + 'iouring_entries' => 1024, + 'iouring_workers' => 16, + 'iouring_flag' => SWOOLE_IOURING_SQPOLL ]); ``` @@ -46,6 +48,25 @@ $server->set([ !> 如果传入的值过大,内核会抛出异常并且终止程序。 +!> 当系统安装了`liburing`和编译``Swoole v6.0`以上的版本,开启了`--enable-iouring`之后才能使用。 + +### iouring_workers + +?> 设置`io_uring`的工作线程数,默认值是`CPU 核数 * 4`。 + +!> 如果传入的值过大,内核会抛出异常并且终止程序。 + !> 当系统安装了`liburing`和编译`Swoole`开启了`--enable-iouring`之后才能使用。 -!> 当系统安装了`liburing`和编译``Swoole v6.0`以上的版本,开启了`--enable-iouring`之后才能使用。 +### iouring_flag + +?> 设置`io_uring`的工作模式,默认值为`SWOOLE_IOURING_DEFAULT`。 + +- `SWOOLE_IOURING_DEFAULT`,中断驱动模式,可通过系统调用`io_uring_enter`提交`I/O`请求,然后直接检查完成队列状态判断是否完成。 +- `SWOOLE_IOURING_SQPOLL`,内核轮询模式,内核会创建内核线程用于提交和收割`I/O`请求,几乎完全消除用户态内核态上下文切换,性能较好。 + +!> 如果传入的模式不正确,内核会统一使用`SWOOLE_IOURING_DEFAULT`中断驱动模式。 + +!> `SWOOLE_IOURING_SQPOLL`是通过牺牲一部分CPU性能换取更高的磁盘读写性能(IOPS),因此QPS会比默认模式差。 + +!> 如果服务压力不大,可以使用`SWOOLE_IOURING_DEFAULT`获取更高的QPS,如果确定服务性能瓶颈是在磁盘,可以使用`SWOOLE_IOURING_SQPOLL`。 diff --git a/public/zh-cn/http_server.md b/public/zh-cn/http_server.md index 13c1208..a350fc9 100644 --- a/public/zh-cn/http_server.md +++ b/public/zh-cn/http_server.md @@ -992,7 +992,7 @@ $server->set([ ### upload_max_filesize -?> **设置上传文件的最大值** +?> **设置上传文件的最大值,设置该值后,上传文件大小大于`package_max_length`时程序不会报错,而是将会文件内容存储到临时文件中,不保存在内存中,方便大文件上传。** ```php $server->set([ diff --git a/public/zh-cn/memory/atomic.md b/public/zh-cn/memory/atomic.md index 235153d..5af0902 100644 --- a/public/zh-cn/memory/atomic.md +++ b/public/zh-cn/memory/atomic.md @@ -1,4 +1,4 @@ -# 进程/线程间无锁计数器 Atomic +# 无锁计数器 Atomic `Atomic`是`Swoole`底层提供的原子计数操作类,可以方便整数的无锁原子增减。 @@ -58,9 +58,11 @@ Swoole\Atomic::__construct(int $init_value = 0); * **默认值**:`0` * **其它值**:无 -!> -`Atomic`只能操作`32`位无符号整数,最大支持`42`亿,不支持负数; --在`Server`中使用原子计数器,必须在`Server->start`前创建; --在[Process](/process/process)中使用原子计数器,必须在`Process->start`前创建。 +!> `Atomic`只能操作`32`位无符号整数,最大支持`42`亿,不支持负数。 + +!> 在`Server`中使用原子计数器,必须在`Server->start`前创建。 + +!> 在[Process](/process/process)中使用原子计数器,必须在`Process->start`前创建。 ### add() @@ -178,8 +180,11 @@ Swoole\Atomic->wait(float $timeout = 1.0): bool `wait`会阻塞整个进程而不是协程,因此请勿在协程环境中使用`Atomic->wait()`避免引起进程挂起。 -!> -使用`wait/wakeup`特性时,原子计数的值只能为`0`或`1`,否则会导致无法正常使用; --当然原子计数的值为`1`时,表示不需要进入等待状态,资源当前就是可用。`wait`函数会立即返回`true`。 +!> 使用`wait/wakeup`特性时,原子计数的值只能为`0`或`1`,否则会导致无法正常使用。 + +!> 当然原子计数的值为`1`时,表示不需要进入等待状态,资源当前就是可用。`wait`函数会立即返回`true`。 + +!> `wait`会阻塞整个进程而不是协程,因此请勿在协程环境中使用该函数,避免引起进程挂起。 * **使用示例** diff --git a/public/zh-cn/memory/lock.md b/public/zh-cn/memory/lock.md index 7163109..3b25a6a 100644 --- a/public/zh-cn/memory/lock.md +++ b/public/zh-cn/memory/lock.md @@ -1,17 +1,9 @@ -# 进程/线程间锁 Lock +# 锁 Lock -* `PHP`代码中可以很方便地创建一个锁`Swoole\Lock`,用来实现数据同步。`Lock`类支持`5`种锁的类型。 -* 多线程模式需要使用`Swoole\Thread\Lock`,除了命名空间不一样,其接口与 `Swoole\Lock` 完全一致。 - -锁类型 | 说明 ----|--- -SWOOLE_MUTEX | 互斥锁 -SWOOLE_RWLOCK | 读写锁 -SWOOLE_SPINLOCK | 自旋锁 -SWOOLE_FILELOCK | 文件锁(废弃) -SWOOLE_SEM | 信号量(废弃) - -!> 请勿在[onReceive](/server/events?id=onreceive)等回调函数中创建锁,否则内存会持续增长,造成内存泄漏。 +* 使用`Swoole`提供的锁可以很方便代码中实现数据同步。 +* 多进程模式下请使用`Swoole\Lock`,多线程模式下请使用`Swoole\Thread\Lock`,除了命名空间不一样,其接口完全一致。 +* `swoole6.0`引入协程锁`Swoole\Coroutine\Lock`,使得跨进程/线程之间的协程加锁不再阻塞进程,协程锁接口与多进程锁和多线程锁略有不同。 +* 该协程锁默认通过`原子计数`和`sleep`实现可重入的互斥锁,如果`linux`内核为6.7以上,`liburing`版本为2.6以上,编译时`swoole6.0`开启了`--enable-iouring`,协程锁的底层将会替换成`io_uring`的`futex`特性,相关的配置参数可以查看[文件异步操作 - 配置](/file/setting?id=iouring_entries)。 ## 使用示例 @@ -38,27 +30,6 @@ sleep(1); echo "[Master]exit\n"; ``` -## 警告 - -!> 在协程中无法使用锁,请谨慎使用,不要在`lock`和`unlock`操作中间使用可能引起协程切换的`API`。 - -### 错误示例 - -!> 此代码在协程模式下`100%`死锁。 - -```php -$lock = new Swoole\Lock(); -$c = 2; - -while ($c--) { - go(function () use ($lock) { - $lock->lock(); - Co::sleep(1); - $lock->unlock(); - }); -} -``` - ## 方法 ### __construct() @@ -71,19 +42,22 @@ Swoole\Lock::__construct(int $type = SWOOLE_MUTEX, string $lockfile = ''); !> 不要循环创建/销毁锁的对象,否则会发生内存泄漏。 +!> 协程锁的构造函数不需要传入任何参数。 + +!> 每一种类型的锁支持的方法都不一样。如读写锁、文件锁可以支持`$lock->lock_read()`。另外除文件锁外,其他类型的锁必须在父进程内创建,这样`fork`出的子进程之间才可以互相争抢锁。 + * **参数** * **`int $type`** * **功能**:锁的类型 * **默认值**:`SWOOLE_MUTEX`【互斥锁】 - * **其它值**:无 + * **其它值**:`读写锁 SWOOLE_RWLOCK`,`自旋锁 SWOOLE_SPINLOCK`,`文件锁 SWOOLE_FILELOCK (已废弃)`,`信号量 SWOOLE_SEM(已废弃)` * **`string $lockfile`** * **功能**:指定文件锁的路径【当类型为`SWOOLE_FILELOCK`时必须传入】 * **默认值**:无 * **其它值**:无 -!> 每一种类型的锁支持的方法都不一样。如读写锁、文件锁可以支持`$lock->lock_read()`。另外除文件锁外,其他类型的锁必须在父进程内创建,这样`fork`出的子进程之间才可以互相争抢锁。 ### lock() @@ -92,6 +66,7 @@ Swoole\Lock::__construct(int $type = SWOOLE_MUTEX, string $lockfile = ''); ```php Swoole\Lock->lock(): bool ``` +* 如果是协程锁,当其他`进程`的协程持有锁,那当前协程`不会阻塞`,而是会让出CPU,等待`唤醒`。 ### trylock() @@ -108,14 +83,6 @@ Swoole\Lock->trylock(): bool !> `SWOOlE_SEM` 信号量没有`trylock`方法 -### unlock() - -释放锁。 - -```php -Swoole\Lock->unlock(): bool -``` - ### lock_read() 只读加锁。 @@ -128,7 +95,9 @@ Swoole\Lock->lock_read(): bool * 但不能`$lock->lock()`或`$lock->trylock()`,这两个方法是获取独占锁,在独占锁加锁时,其他进程无法再进行任何加锁操作,包括读锁; * 当另外一个进程获得了独占锁(调用`$lock->lock()`/`$lock->trylock()`)时,`$lock->lock_read()`会发生阻塞,直到持有独占锁的进程释放锁。 -!> 只有`SWOOLE_RWLOCK`和`SWOOLE_FILELOCK`类型的锁支持只读加锁 +!> 协程锁没有`lock_read()`函数。 + +!> 只有`SWOOLE_RWLOCK`和`SWOOLE_FILELOCK`类型的锁支持只读加锁。 ### trylock_read() @@ -138,6 +107,8 @@ Swoole\Lock->lock_read(): bool Swoole\Lock->trylock_read(): bool ``` +!> 协程锁没有`trylock_read()`函数。 + !> 调用会立即返回,必须检测返回值以确定是否拿到了锁。 ### lockwait() @@ -161,4 +132,36 @@ Swoole\Lock->lockwait(float $timeout = 1.0): bool * 在规定的时间内未获得锁,返回`false` * 加锁成功返回`true` +!> 协程锁没有`lockwait()`函数。 + !> 只有`Mutex`类型的锁支持`lockwait` + +### unlock() + +释放锁。 + +```php +Swoole\Lock->unlock(): bool +``` + +## 注意 +!> 请勿在[onReceive](/server/events?id=onreceive)等回调函数中创建锁,否则内存会持续增长,造成内存泄漏。 + +!> `原子计数`和`sleep`实现的协程锁比起`io_uring`实现的协程锁,性能会较差,因为它会带来不必要的上下文切换。 + +!> 加锁和解锁必须在同一个进程/线程/协程中完成,不然会破坏竞争条件,无法有效实现互斥。 + +!> 如果不是使用协程锁,此代码在协程模式下`100%`死锁。 + +```php +$lock = new Swoole\Lock(); +$c = 2; + +while ($c--) { + go(function () use ($lock) { + $lock->lock(); + Co::sleep(1); + $lock->unlock(); + }); +} +``` diff --git a/public/zh-cn/process/process.md b/public/zh-cn/process/process.md index 2668d05..4e050be 100644 --- a/public/zh-cn/process/process.md +++ b/public/zh-cn/process/process.md @@ -17,7 +17,7 @@ Swoole提供的进程管理模块,用来替代PHP的`pcntl` * 可以方便的实现进程间通讯 * 支持重定向标准输入和输出,在子进程内`echo`不会打印屏幕,而是写入管道,读键盘输入可以重定向为管道读取数据 * 提供了[exec](/process/process?id=exec)接口,创建的进程可以执行其他程序,与原`PHP`父进程之间可以方便的通信 -* 在协程环境中无法使用`Process`模块,可以使用`runtime hook`+`proc_open`实现,参考[协程进程管理](/coroutine/proc_open) +* 不能在协程中使用`Process`模块,参考[协程中创建进程](/coroutine/notice?id=协程中创建进程) ### 使用示例 @@ -44,44 +44,44 @@ echo 'Parent #' . getmypid() . ' exit' . PHP_EOL; ## 属性 -### pipe +### id -[unixSocket](/learn?id=什么是IPC)的文件描述符。 +当前进程`id`。 ```php -public int $pipe; +public int $id; ``` -### msgQueueId +### pid -消息队列的`id`。 +当前进程的进程`pid`。 ```php -public int $msgQueueId; +public int $pid; ``` -### msgQueueKey +### pipe -消息队列的`key`。 +[unixSocket](/learn?id=什么是IPC)的文件描述符。 ```php -public string $msgQueueKey; +public int $pipe; ``` -### pid +### msgQueueId -当前进程的`pid`。 +消息队列的`id`。 ```php -public int $pid; +public int $msgQueueId; ``` -### id +### msgQueueKey -当前进程`id`。 +消息队列的`key`。 ```php -public int $id; +public string $msgQueueKey; ``` ## 常量 @@ -119,7 +119,7 @@ Swoole\Process->__construct(callable $function, bool $redirect_stdin_stdout = fa * **其它值**:`0`、`SOCK_STREAM` * **`bool $enable_coroutine`** - * **功能**:在`callback function`中启用协程,开启后可以直接在子进程的函数中使用协程API + * **功能**:在`callback function`中启用协程,开启后可以直接在子进程的函数中使用协程API或者开启[一键协程化](/runtime),避免阻塞函数阻塞进程。 * **默认值**:`false` * **其它值**:`true` * **版本影响**:Swoole版本 >= v4.3.0 @@ -266,7 +266,7 @@ Swoole\Process->setTimeout(float $seconds): bool 设置消息队列套接字是否阻塞。 ```php -Swoole\Process->setBlocking(bool $$blocking): void +Swoole\Process->setBlocking(bool $blocking): void ``` * **参数** diff --git a/public/zh-cn/server/methods.md b/public/zh-cn/server/methods.md index 0a1d3ec..339eb6d 100644 --- a/public/zh-cn/server/methods.md +++ b/public/zh-cn/server/methods.md @@ -220,6 +220,7 @@ Swoole\Server->addProcess(Swoole\Process $process): int -用户进程内不能使用`Server->task/taskwait`接口。 -用户进程内可以使用`Server->send/close`等接口。 -用户进程内应当进行`while(true)`(如下边的示例)或[EventLoop](/learn?id=什么是eventloop)循环(例如创建个定时器),否则用户进程会不停地退出重启。 + -必须在`Server->start()`执行之前使用`addProcess`,否则用户进程不会启动的。 * **生命周期** diff --git a/public/zh-cn/server/setting.md b/public/zh-cn/server/setting.md index 7856fa7..e917b60 100644 --- a/public/zh-cn/server/setting.md +++ b/public/zh-cn/server/setting.md @@ -166,40 +166,6 @@ $server->set([ ]); ``` -### hook_flags - -?> **设置`一键协程化`Hook的函数范围。**【默认值:不hook】 - -!> Swoole版本为 `v4.5+` 或 [4.4LTS](https://github.com/swoole/swoole-src/tree/v4.4.x) 可用,详情参考[一键协程化](/runtime) - -```php -$server->set([ - 'hook_flags' => SWOOLE_HOOK_SLEEP, -]); -``` -底层支持以下协程化项,可使用`SWOOLE_HOOK_ALL`表示协程化全部: - -* `SWOOLE_HOOK_TCP` -* `SWOOLE_HOOK_UNIX` -* `SWOOLE_HOOK_UDP` -* `SWOOLE_HOOK_UDG` -* `SWOOLE_HOOK_SSL` -* `SWOOLE_HOOK_TLS` -* `SWOOLE_HOOK_SLEEP` -* `SWOOLE_HOOK_FILE` -* `SWOOLE_HOOK_STREAM_FUNCTION` -* `SWOOLE_HOOK_BLOCKING_FUNCTION` -* `SWOOLE_HOOK_PROC` -* `SWOOLE_HOOK_CURL` -* `SWOOLE_HOOK_NATIVE_CURL` -* `SWOOLE_HOOK_SOCKETS` -* `SWOOLE_HOOK_STDIO` -* `SWOOLE_HOOK_PDO_PGSQL` -* `SWOOLE_HOOK_PDO_ODBC` -* `SWOOLE_HOOK_PDO_ORACLE` -* `SWOOLE_HOOK_PDO_SQLITE` -* `SWOOLE_HOOK_ALL` - ### enable_preemptive_scheduler ?> 设置打开协程抢占式调度,避免其中一个协程执行时间过长导致其他协程饿死,协程最大执行时间为`10ms`。 @@ -230,6 +196,31 @@ $server->set([ ?> 工作线程最大空闲时间,单位为秒。 +### iouring_entries + +?> 设置`io_uring`的队列大小,默认为`8192`,如果传入的值不是`2的次方数`,内核会修改为最接近的,大于该值的`2的次方数`。 + +!> 如果传入的值过大,内核会抛出异常并且终止程序。 + +!> 当系统安装了`liburing`和编译`Swoole`开启了`--enable-iouring`之后才能使用。 + +### iouring_workers + +?> 设置`io_uring`的工作线程数,默认值是`CPU 核数 * 4`。 + +!> 如果传入的值过大,内核会抛出异常并且终止程序。 + +!> 当系统安装了`liburing`和编译`Swoole`开启了`--enable-iouring`之后才能使用。 + +### iouring_flag + +?> 设置`io_uring`的工作模式,默认值为`SWOOLE_IOURING_DEFAULT`。 + +- `SWOOLE_IOURING_DEFAULT`,中断驱动模式,可通过系统调用`io_uring_enter`提交`I/O`请求,然后直接检查完成队列状态判断是否完成。 +- `SWOOLE_IOURING_SQPOLL`,内核轮询模式,内核会创建内核线程用于提交和收割`I/O`请求,几乎完全消除用户态内核态上下文切换,性能较好。 + +!> 如果传入的模式不正确,内核会统一使用`SWOOLE_IOURING_DEFAULT`中断驱动模式。 + ### reactor_num ?> **设置启动的 [Reactor](/learn?id=reactor线程) 线程数。**【默认值:`CPU`核数】 @@ -1526,7 +1517,7 @@ $server->set([ * 当`enable_coroutine`设置为`true`时,底层自动在[onRequest](/http_server?id=on)回调中创建协程,开发者无需自行使用`go`函数[创建协程](/coroutine/coroutine?id=create) * 当`enable_coroutine`设置为`false`时,底层不会自动创建协程,开发者如果要使用协程,必须使用`go`自行创建协程,如果不需要使用协程特性,则处理方式与`Swoole1.x`是100%一致的 -* 注意,这个开启只是说明Swoole会通过协程去处理请求,如果事件中含有阻塞函数,那需要提前开启[一键协程化](/runtime),将`sleep`,`mysqlnd`这些阻塞的函数或者扩展开启协程化 +* 注意,这个开启只是说明Swoole会通过协程去处理请求,如果事件中含有阻塞函数,那需要提前配置`hook_flags`或者开启[一键协程化](/runtime),将`sleep`,`mysqlnd`这些阻塞的函数或者扩展开启协程化 ```php $server = new Swoole\Http\Server("127.0.0.1", 9501); @@ -1552,6 +1543,40 @@ $server->on("request", function ($request, $response) { $server->start(); ``` +### hook_flags + +?> **设置`一键协程化`Hook的函数范围。**【默认值:不hook】 + +!> Swoole版本为 `v4.5+` 或 [4.4LTS](https://github.com/swoole/swoole-src/tree/v4.4.x) 可用,详情参考[一键协程化](/runtime) + +```php +$server->set([ + 'hook_flags' => SWOOLE_HOOK_SLEEP, +]); +``` +底层支持以下协程化项,可使用`SWOOLE_HOOK_ALL`表示协程化全部: + +* `SWOOLE_HOOK_TCP` +* `SWOOLE_HOOK_UNIX` +* `SWOOLE_HOOK_UDP` +* `SWOOLE_HOOK_UDG` +* `SWOOLE_HOOK_SSL` +* `SWOOLE_HOOK_TLS` +* `SWOOLE_HOOK_SLEEP` +* `SWOOLE_HOOK_FILE` +* `SWOOLE_HOOK_STREAM_FUNCTION` +* `SWOOLE_HOOK_BLOCKING_FUNCTION` +* `SWOOLE_HOOK_PROC` +* `SWOOLE_HOOK_CURL` +* `SWOOLE_HOOK_NATIVE_CURL` +* `SWOOLE_HOOK_SOCKETS` +* `SWOOLE_HOOK_STDIO` +* `SWOOLE_HOOK_PDO_PGSQL` +* `SWOOLE_HOOK_PDO_ODBC` +* `SWOOLE_HOOK_PDO_ORACLE` +* `SWOOLE_HOOK_PDO_SQLITE` +* `SWOOLE_HOOK_ALL` + ### send_yield ?> **当发送数据时缓冲区内存不足时,直接在当前协程内[yield](/coroutine?id=协程调度),等待数据发送完成,缓存区清空时,自动[resume](/coroutine?id=协程调度)当前协程,继续`send`数据。**【默认值:在[dispatch_mod](/server/setting?id=dispatch_mode) 2/4时候可用,并默认开启】 diff --git a/public/zh-cn/thread/arraylist.md b/public/zh-cn/thread/arraylist.md index 17be801..b8b714e 100644 --- a/public/zh-cn/thread/arraylist.md +++ b/public/zh-cn/thread/arraylist.md @@ -127,3 +127,18 @@ Swoole\Thread\ArrayList()->toArray(): array ```php Swoole\Thread\ArrayList()->clean(): void ``` + +### find() +根据值搜索`ArrayList`中对应的数字key。 + +```php +Swoole\Thread\ArrayList()->find(mixed $value): int +``` +* **参数** + * `mixed $value` + * 功能:需要搜索的值。 + * 默认值:无。 + * 其它值:无。 + +* **返回值** + * 返回该值对应的索引。 diff --git a/public/zh-cn/thread/barrier.md b/public/zh-cn/thread/barrier.md index 7fe7255..af9345b 100644 --- a/public/zh-cn/thread/barrier.md +++ b/public/zh-cn/thread/barrier.md @@ -1,11 +1,14 @@ -# 线程同步执行屏障 Barrier +# 同步执行屏障 Barrier + +## 线程同步屏障 `Thread\Barrier` 是一种线程同步的机制。它允许多个线程在特定的点上进行同步,确保所有线程在某个临界点(障碍)之前都完成了自己的任务。只有当所有参与的线程都到达这个障碍时,它们才能继续执行后续的代码。 例如我们创建了`4`个线程,希望这些线程全部就绪后一起执行任务,就像跑步比赛中裁判的发令枪,在发出信号之后同时起跑。这就可以用`Thread\Barrier`实现。 +!> 该线程同步屏障会导致线程挂起,因此不能用于多协程同步。 -## 示例 +### 示例 ```php use Swoole\Thread; use Swoole\Thread\Barrier; @@ -29,9 +32,9 @@ if (empty($args)) { } ``` -## 方法 +### 方法 -### __construct() +#### __construct() 构造方法 ```php @@ -46,10 +49,84 @@ Thread\Barrier()->__construct(int $count): void 执行`wait`操作的线程数量必须与设置的计数一致,否则所有线程均会阻塞。 -### wait() +#### wait() 阻塞等待其他线程,直到所有线程均处于`wait`状态时,会同时唤醒所有等待的线程,继续向下执行。 ```php Thread\Barrier()->wait(): void ``` + +## 协程同步屏障 + +在 [Swoole Library](https://github.com/swoole/library) 中底层提供了一个更便捷的协程并发管理工具:`Coroutine\Barrier` 协程屏障,或者叫协程栅栏。基于 `PHP` 引用计数和 `Coroutine API` 实现。 + +相比于[Coroutine\WaitGroup](/coroutine/wait_group),`Coroutine\Barrier`使用更简单一些,只需通过参数传递或者闭包的`use`语法,引入子协程函数上即可。 + +!> Swoole 版本 >= v4.5.5 时可用。 + +!> 该协程屏障只能用于单进程或者单线程中的多协程同步,主要作用还是让主协程等待全部子协程完成任务后退出。 + +### 使用示例 + +```php +use Swoole\Coroutine\Barrier; +use Swoole\Coroutine\System; +use function Swoole\Coroutine\run; +use Swoole\Coroutine; + +run(function () { + $barrier = Barrier::make(); + + $count = 0; + $N = 4; + + foreach (range(1, $N) as $i) { + Coroutine::create(function () use ($barrier, &$count) { + System::sleep(0.5); + $count++; + }); + } + + Barrier::wait($barrier); + + assert($count == $N); +}); +``` + +### 方法 + +#### make() +生成一个协程屏障。 + +```php +Coroutine\Barrier::make(): self +``` + +#### wait() +等待所有协程就绪 + +```php +Coroutine\Barrier::wait(Barrier &$barrier, float $timeout = -1): void +``` + +* **参数** + * `int $barrier` + * 功能:由`Coroutine\Barrier::make()`返回的协程屏障。 + * 默认值:无。 + * 其它值:无。 + * `float $timeout` + * 功能:超时时间。 + * 默认值:-1,表示永不超时。 + * 其它值:无。 + +### 执行流程 + +* 先使用`Barrier::make()`创建了一个新的协程屏障 +* 在子协程用使用`use`语法传递屏障,增加引用计数 +* 在需要等待的位置加入`Barrier::wait($barrier)`,这时会自动挂起当前协程,等待引用该协程屏障的子协程退出 +* 子协程退出时会减少`$barrier`对象的引用计数,直到为`0` +* 当所有子协程完成了任务处理并退出时,`$barrier`对象引用计数为`0`,在`$barrier`对象析构函数中底层会自动恢复挂起的协程,从`Barrier::wait($barrier)`函数中返回 + +`Coroutine\Barrier` 是一个比 [WaitGroup](/coroutine/wait_group) 和 [Channel](/coroutine/channel) 更易用的并发控制器,大幅提升了 `PHP` 并发编程的用户体验。 + diff --git a/public/zh-cn/thread/info.md b/public/zh-cn/thread/info.md index 9abb25f..f406287 100644 --- a/public/zh-cn/thread/info.md +++ b/public/zh-cn/thread/info.md @@ -1,5 +1,32 @@ # 方法与属性 +## 属性 + +### id + +通过此对象属性获取子线程的 `ID`,该属性是`int`类型。 + +> 此属性仅用在父线程,子线程无法获得`$thread`对象,应使用`Thread::getId()`静态方法获取线程的`ID` + +```php +$thread = new Swoole\Thread(__FILE__, $i); +var_dump($thread->id); +``` + +## 常量 + +名称 | 作用 +---|--- +`Thread::HARDWARE_CONCURRENCY` | 硬件并发线程数量,一般为`CPU`核数 +`Thread::API_NAME` | 线程 `API` 名称,例如 `POSIX Threads` +`Thread::SCHED_OTHER` | 线程调度策略 `SCHED_OTHER` +`Thread::SCHED_FIFO` | 线程调度策略 `SCHED_FIFO` +`Thread::SCHED_RR` | 线程调度策略 `SCHED_RR` +`Thread::SCHED_BATCH` | 线程调度策略 `SCHED_BATCH` +`Thread::SCHED_ISO` | 线程调度策略 `SCHED_ISO` +`Thread::SCHED_IDLE` | 线程调度策略 `SCHED_IDLE` +`Thread::SCHED_DEADLINE` | 线程调度策略 `SCHED_DEADLINE` + ## 方法 ### __construct() @@ -178,16 +205,16 @@ Swoole\Thread->setName(string $name): bool * 失败返回`false`,使用`swoole_last_error()`获取错误信息 ```shell -$ ps aux|grep -v grep|grep pool.php -swoole   2226813  0.1  0.1 423860 49024 pts/6    Sl+  17:38   0:00 php pool.php +$ ps aux|grep -v grep|grep pool.php +swoole 2226813 0.1 0.1 423860 49024 pts/6 Sl+ 17:38 0:00 php pool.php -$ ps -T -p 2226813 -    PID    SPID TTY          TIME CMD -2226813 2226813 pts/6    00:00:00 Master Thread -2226813 2226814 pts/6    00:00:00 Worker Thread 0 -2226813 2226815 pts/6    00:00:00 Worker Thread 1 -2226813 2226816 pts/6    00:00:00 Worker Thread 2 -2226813 2226817 pts/6    00:00:00 Worker Thread 3 +$ ps -T -p 2226813 + PID SPID TTY TIME CMD +2226813 2226813 pts/6 00:00:00 Master Thread +2226813 2226814 pts/6 00:00:00 Worker Thread 0 +2226813 2226815 pts/6 00:00:00 Worker Thread 1 +2226813 2226816 pts/6 00:00:00 Worker Thread 2 +2226813 2226817 pts/6 00:00:00 Worker Thread 3 ``` ### getNativeId() @@ -200,31 +227,3 @@ Swoole\Thread->getNativeId(): int 此函数在`Linux`系统会调用`gettid()`系统调用,获取一个类似于操作系统线程`ID`,是一个短整数。当进程线程销毁时可能会被操作系统服用。 此`ID`可以用于`gdb`、`strace`调试,例如`gdb -p $tid`。另外还可以读取`/proc/{PID}/task/{ThreadNativeId}`获取线程的执行信息。 - -## 属性 - -### id - -通过此对象属性获取子线程的 `ID`,该属性是`int`类型。 - -> 此属性仅用在父线程,子线程无法获得`$thread`对象,应使用`Thread::getId()`静态方法获取线程的`ID` - -```php -$thread = new Swoole\Thread(__FILE__, $i); -var_dump($thread->id); -``` - -## 常量 - -名称 | 作用 ----|--- -`Thread::HARDWARE_CONCURRENCY` | 硬件并发线程数量,一般为`CPU`核数 -`Thread::API_NAME` | 线程 `API` 名称,例如 `POSIX Threads` -`Thread::SCHED_OTHER` | 线程调度策略 `SCHED_OTHER` -`Thread::SCHED_FIFO` | 线程调度策略 `SCHED_FIFO` -`Thread::SCHED_RR` | 线程调度策略 `SCHED_RR` -`Thread::SCHED_BATCH` | 线程调度策略 `SCHED_BATCH` -`Thread::SCHED_ISO` | 线程调度策略 `SCHED_ISO` -`Thread::SCHED_IDLE` | 线程调度策略 `SCHED_IDLE` -`Thread::SCHED_DEADLINE` | 线程调度策略 `SCHED_DEADLINE` - diff --git a/public/zh-cn/thread/map.md b/public/zh-cn/thread/map.md index cc9056a..ea09301 100644 --- a/public/zh-cn/thread/map.md +++ b/public/zh-cn/thread/map.md @@ -174,3 +174,18 @@ Swoole\Thread\Map()->toArray(): array ```php Swoole\Thread\Map()->clean(): void ``` + +### find() +根据值搜索`Map`中对应的key。 + +```php +Swoole\Thread\Map()->find(mixed $value): mixed +``` +* **参数** + * `mixed $value` + * 功能:需要搜索的值。 + * 默认值:无。 + * 其它值:无。 + +* **返回值** + * 返回该值对应的key。 diff --git a/public/zh-cn/thread/thread.md b/public/zh-cn/thread/thread.md index 5165133..b3dffd9 100644 --- a/public/zh-cn/thread/thread.md +++ b/public/zh-cn/thread/thread.md @@ -3,36 +3,36 @@ 从 `6.0` 版本开始提供了多线程支持,可使用线程 `API` 来代替多进程。相比多进程,`Thread` 提供了更丰富的并发数据容器, 在开发游戏服务器、通信服务器方面更方便。 -- `PHP` 必须为 `ZTS` 模式,编译 `PHP` 时需要加入 `--enable-zts` -- 编译 `Swoole` 时需要增加 `--enable-swoole-thread` 编译选项 +- `PHP` 必须为 `ZTS` 模式,编译 `PHP` 时需要加入 `--enable-zts`。 +- 编译 `Swoole` 时需要增加 `--enable-swoole-thread` 编译选项。 ## 资源隔离 `Swoole` 线程与 `Node.js Worker Thread` 是相似的,在子线程中会创建一个全新的 `ZendVM` 环境。 子线程不会从父线程继承任何资源,因此在子线程中下列内容已被清空,需要重新创建或设置。 -- 已加载的 `PHP` 文件,需要重新 `include/require` 加载 -- 需要重新注册`autoload` 函数 -- 类、函数、常量,将被清空,需重新加载 `PHP` 文件创建 -- 全局变量,例如 `$GLOBALS`、`$_GET/$_POST` 等,将被重置 -- 类的静态属性、函数的静态变量,将重置为初始值 -- 一些`php.ini` 选项,例如 `error_reporting()` 需要在子线程中重新设置 +- 已加载的 `PHP` 文件,需要重新 `include/require` 加载。 +- 需要重新注册`autoload` 函数。 +- 类、函数、常量,将被清空,需重新加载 `PHP` 文件创建。 +- 全局变量,例如 `$GLOBALS`、`$_GET/$_POST` 等,将被重置。 +- 类的静态属性、函数的静态变量,将重置为初始值。 +- 一些`php.ini` 选项,例如 `error_reporting()` 需要在子线程中重新设置。 ## 不可用特性 -在多线程模式下,下列特性仅支持在主线程中操作,无法在子线程中执行: +在多线程模式下,下列特性仅支持在主线程中操作,主线程的设置会影响到子线程: -- `swoole_async_set()` 修改线程参数 -- `Swoole\Runtime::enableCoroutine()` 和 `Swoole\Runtime::setHookFlags()` -- 仅主线程可设置信号监听,包括 `Process::signal()` 和 `Coroutine\System::waitSignal()` 不能在子线程中使用 -- 仅主线程可创建异步服务器,包括 `Server`、`Http\Server`、`WebSocket\Server` 等不能在子线程中使用 +- 只能由主线程通过`swoole_async_set()` 设置线程参数 +- 只能由主线程通过`Swoole\Runtime::enableCoroutine()` 和 `Swoole\Runtime::setHookFlags()`设置协程参数。 +- 仅主线程可设置信号监听,包括 `Process::signal()` 和 `Coroutine\System::waitSignal()` 不能在子线程中设置。 +- 仅主线程可创建异步服务器,包括 `Server`、`Http\Server`、`WebSocket\Server` 等不能在子线程中使用。 -除此之外,`Runtime Hook` 在多线程模式下开启后将无法关闭。 -## 致命错误 -当主线程退出时,若依然存在活跃的子线程,将抛出一个致命错误,退出的状态码为:`200`,错误信息如下: -``` -Fatal Error: 2 active threads are running, cannot exit safely. -``` + +## 注意 +!> 除此之外,`Runtime Hook` 在多线程模式下开启后将无法关闭。 + +!> 当主线程退出时,若依然存在活跃的子线程,将抛出一个致命错误,退出的状态码为:`200`,错误信息如下: +`Fatal Error: 2 active threads are running, cannot exit safely` ## 查看是否开启线程支持 @@ -43,7 +43,7 @@ Copyright (c) The PHP Group Zend Engine v4.1.23, Copyright (c) Zend Technologies ``` -`(ZTS)` 表示已启用线程安全 +`(ZTS)` 表示已启用线程安全。 ```shell php --ri swoole @@ -53,7 +53,7 @@ Swoole => enabled thread => enabled ``` -`thread => enabled` 表示已开启多线程支持 +`thread => enabled` 表示已开启多线程支持。 ### 创建多线程 ```php @@ -82,11 +82,11 @@ if (empty($args)) { ``` ### 线程 + 服务端(异步风格) -- 所有工作进程将使用线程来运行,包括 `Worker`、`Task Worker`、`User Process` -- 新增 `SWOOLE_THREAD` 运行模式,启用后将使用线程代替进程运行 -- 增加了 [bootstrap](/server/setting?id=bootstrap) 和 [init_arguments](/server/setting?id=init_arguments) 两项配置,用于设置工作线程的入口脚本文件、线程共享数据 -- 必须在主线程中创建 `Server`,可在回调函数中创建新的 `Thread` 执行其他任务 -- `Server::addProcess()` 进程对象不支持标准输入输出重定向 +- 所有工作进程将使用线程来运行,包括 `Worker`、`Task Worker`、`User Process`。 +- 新增 `SWOOLE_THREAD` 运行模式,启用后将使用线程代替进程运行。 +- 增加了 [bootstrap](/server/setting?id=bootstrap) 和 [init_arguments](/server/setting?id=init_arguments) 两项配置,用于设置工作线程的入口脚本文件、线程共享数据。 +- 必须在主线程中创建 `Server`,可在回调函数中创建新的 `Thread` 执行其他任务。 +- `Server::addProcess()` 进程对象不支持标准输入输出重定向。 ```php use Swoole\Process; diff --git a/public/zh-cn/version/log.md b/public/zh-cn/version/log.md index 6e50aed..bfbde5f 100644 --- a/public/zh-cn/version/log.md +++ b/public/zh-cn/version/log.md @@ -8,6 +8,7 @@ * 8.1 * 8.2 * 8.3 +* 8.4 ## 建议使用的Swoole版本 `Swoole6.x`和`Swoole5.x` @@ -31,6 +32,184 @@ php --ri swoole ## v6.0.0 +### 新特性: +- `Swoole`支持多线程模式,当`php`是`zts`模式,编译`Swoole`时开启`--enable-swoole-thread`时,就能使用多线程模式。 +- 新增创建线程类`Swoole\Thread`。 @matyhtf +- 新增线程锁`Swoole\Thread\Lock`。 @matyhtf +- 新增线程原子计数`Swoole\Thread\Atomic`,`Swoole\Thread\Atomic\Long`。 @matyhtf +- 新增安全并发容器`Swoole\Thread\Map`,`Swoole\Thread\ArrayList`,`Swoole\Thread\Queue`。 @matyhtf +- 文件异步操作支持了使用`iouring作为文件异步操作的底层引擎`,安装了`liburing`和编译`Swoole`时开启`--enable-iouring`,`file_get_contents`,`file_put_contents`,`fopen`,`fclose`,`fread`,`fwrite`,`mkdir`,`unlink`,`fsync`,`fdatasync`,`rename`,`fstat`,`lstat`,`filesize`这些函数的异步操作将会由`iouring`实现。 @matyhtf @NathanFreeman +- 升级`Boost Context`版本到1.84。现在,龙芯CPU也能够支持协程了。 @NathanFreeman +- 新增`Swoole\Thread\Map::find()`方法。 @matyhtf +- 新增`Swoole\Thread\ArrayList::find()`方法。 @matyhtf +- 新增`Swoole\Thread\ArrayList::offsetUnset()`方法。 @matyhtf +- 新增`Swoole\Process::getAffinity()`方法。 @matyhtf +- 新增`Swoole\Thread::setName()`方法。 @matyhtf +- 新增`Swoole\Thread::setAffinity()`方法。 @matyhtf +- 新增`Swoole\Thread::getAffinity()`方法。 @matyhtf +- 新增`Swoole\Thread::setPriority()`方法。 @matyhtf +- 新增`Swoole\Thread::getPriority()`方法。 @matyhtf +- 新增`Swoole\Thread::gettid()`方法。 +- 文件异步引擎`iouring`支持多线程轮询模式`IORING_SETUP_SQPOLL`。 @NathanFreeman +- 新增`iouring_workers`修改`iouring`线程数。 @NathanFreeman +- 新增`iouring_flags`支持修改`iouring`工作模式。 @NathanFreeman +- 增加`Swoole\Thead\Barrier`多线程同步屏障。@matyhtf +- 增加新的设置cookie的函数。 @matyhtf @NathanFreeman +- 新增`非阻塞,可重入的互斥协程锁”,该锁可以在进程间/线程间使用,且不会阻塞进程/线程。 @NathanFreeman +- `Swoole\Coroutine\Socket::getOption()`支持了`TCP_INFO`选项。 @matyhtf +- `Swoole\Client`同步阻塞客户端支持`http`代理。 @matyhtf +- 新增异步非阻塞的`TCP/UDP/Unixsocket` 客户端`Swoole\Async\Client`。 @matyhtf +- 优化`Swoole\Redis\Server::format`()方法,支持内存零拷贝,支持`redis`嵌套结构。 @matyhtf +- 支持高性能压缩工具`Zstd`,只需要在编译`Swoole`时加上`--enable-zstd`,`http`客户端和服务端之间便可使用`zstd`来压缩响应或者解码响应。 @NathanFreeman + +### Bug修复: +- 修复无法通过`pecl`安装的问题。 @remicollet +- 修复`Swoole\Coroutine\FastCGI\Client`客户端无法设置keepalive。 @NathanFreeman +- 修复请求参数超过`max_input_vars`时会抛出错误导致进程不断重启的问题。 @NathanFreeman +- 修复在协程中使用`Swoole\Event::wait()`导致的未知问题。 @matyhtf +- 修复`proc_open`在协程化的时候不支持pty的问题。 @matyhtf +- 修复`pdo_sqlite`在PHP8.3会出现段错误的问题。 @NathanFreeman +- 修复编译`Swoole`时的无用警告。 @Appla @NathanFreeman +- 修复如果`STDOUT/STDERR`已经关闭时,底层调用zend_fetch_resource2_ex会抛出错误。 @Appla @matyhtf +- 修复无效的`set_tcp_nodelay`配置。 @matyhtf +- 修复文件上传的时候偶尔会触发不可达的分支问题。 @NathanFreeman +- 修复设置了`dispatch_func`,会导致php底层抛出错误的问题。 @NathanFreeman +- 修复AC_PROG_CC_C99在autoconf >= 2.70版本中已过时。 @petk +- 当线程创建失败时,捕获其抛出的异常。 @matyhtf +- 修复`_tsrm_ls_cache`未定义问题。 @jingjingxyk +- 修复在`GCC 14`编译会导致致命错误。 @remicollet +- 修复`Swoole\Http2\Request`动态属性问题。 @guandeng +- 修复`pgsql`协程客户端偶发资源不可用的问题。 @NathanFreeman +- 修复进程重启,没有重置相关参数导致503错误的问题。@matyhtf +- 修复开启`HTTP2`时,`$request->server['request_method']` 与 `$request->getMethod()` 的结果不一致。 @matyhtf +- 修复上传文件时,不正确的`content-type`。 @matyhtf +- 修复`http2`协程客户端的代码错误。 @matyhtf +- 修复`Swoole\Server`缺少属性`worker_id`的问题。 @cjavad +- 修复`config.m4`有关`brotli`错误的问题。 @fundawang +- 修复 多线程下`Swoole\Http\Response::create`无效。 @matyhtf +- 修复`macos`环境下编译错误。 @matyhtf +- 修复线程无法安全退出的问题。 @matyhtf +- 修复多线程模式下,`Swoole\Http\Response`返回响应时间的静态变量没有各个线程各自生成一份的问题。 @matyhtf @NathanFreeman +- 修复因为`PHP-8.4`在ZTS模式下的`超时`特性引起的`Fatal error`问题。 @matyhtf +- 修复`PHP-8.4`的`exit()`函数`hook`。 @remicollet +- 修复`Swoole\Thread::getNativeId()`在`cygwin`无法工作的问题。 @matyhtf +- 修复`Swoole\Coroutine::getaddrinfo()`方法会导致`SIGSEGV`的问题。 @matyhtf +- 修复`runtime tcp`模块不支持动态开启SSL加密的问题。 @matyhtf +- 修复http客户端长时间运行导致超时时间不正确的问题。 @matyhtf +- 修复进程退出之前会导致`Swoole\Table`的互斥锁无法使用的问题。 @matyhtf +- 修复使用命名参数导致`Swoole\Server::stop()`执行失败的问题。 @matyhtf +- 修复`Swoole\Thread\Map::toArray()`函数未复制`key`导致崩溃的问题。 @matyhtf +- 修复`Swoole\Thread\Map`无法删除嵌套的数字键的问题。 @matyhtf + +### 内核优化: +- 移除对`socket structs`的无用检查。 @petk +- 升级swoole Library。 @deminy +- `Swoole\Http\Response`增加对451状态码的支持。 @abnegate +- 同步PHP不同版本的`文件`操作代码。 @NathanFreeman +- 同步PHP不同版本的`pdo`操作代码。 @NathanFreeman +- 优化`Socket::ssl_recv()`的代码。 @matyhtf +- 优化了config.m4,一些配置可以通过`pkg-config`设置依赖库位置。 @NathanFreeman +- 优化`解析请求头`的时候使用动态数组的问题 。 @NathanFreeman +- 优化在多线程模式下,文件描述符`fd`的生命周期问题。 @matyhtf +- 优化协程一些基本逻辑。 @matyhtf +- 升级CI测试的oracle数据库版本。 @gvenzl +- 优化底层`sendfile`的相关逻辑。 @matyhtf +- `config.m4`中用`AC_DEFINE_UNQUOTED`替换`PHP_DEF_HAVE`。 @petk +- 优化多线程模式下,server的`heartbeat`,`shutdown`和`stop`的相关逻辑。 @matyhtf +- 优化`glibc`版本高于2.17时,不需要链接`librt`。 @matyhtf +- 加强`http`客户端可以接受重复的请求头。 @matyhtf +- 优化`Swoole\Http\Response::write()`。 @matyhtf +- `Swoole\Http\Response::write()`现在可以发送`http2`协议。 @matyhtf +- 兼容`PHP8.4`。 @matyhtf @NathanFreeman +- 增加底层`socket`异步写入的能力。 @matyhtf +- 优化`Swoole\Http\Response`。 @NathanFreeman +- 多线程模式下,支持共享php原生`socket`。 @matyhtf +- 优化静态文件服务,修复静态文件路径错误问题。 @matyhtf +- 异步`Server`多线程模式支持重启工作线程。 @matyhtf +- 异步`Server`多线程模式支持在`Manager`线程中开启定时器。 @matyhtf +- 兼容`PHP-8.4`的`curl`扩展。 @matyhtf @NathanFreeman +- 重新封装`Swoole`底层使用`iouring`的代码。 @matyhtf @NathanFreeman +- 优化定时器,使同步进程不依赖于信号。 @matyhtf +- 优化`Swoole\Coroutine\System::waitSignal()`方法,允许同时监听多个信号。 @matyhtf + +### 废弃: +- 不再支持`PHP 8.0`。 +- 不再支持`Swoole\Coroutine\MySQL`协程客户端。 +- 不再支持`Swoole\Coroutine\Redis`协程客户端。 +- 不再支持`Swoole\Coroutine\PostgreSQL`协程客户端。 +- 移除`Swoole\Coroutine\System::fread()`, `Swoole\Coroutine\System::fwrite()`和`Swoole\Coroutine\System::fgets()`方法 + +## v5.1.5 + +### Bug修复: +- 修复php版本大于8.2,需要使用`zend_ini_parse_quantity`解析字符串数字。 @matyhtf +- 修复`pdo_pgsql`协程化的时候,偶发资源不可用的问题。 @NathanFreeman +- 修复`pdo_pgsql`协程化的时候,头文件引用问题。 @NathanFreeman +- 修复不正确的相对路径检查,以避免绕过路径验证。 @matyhtf +- 修复高并发环境下,进程重启会导致并发数不正确。 @matyhtf + +### 内核优化: +- 同步`php8.3 curl`的一些相关代码。 @NathanFreeman +- 修复`process`模块核心测试错误。 @NathanFreeman +- 在`SWOOLE_BASE`模式下,所有的连接都应该在`PHP RSHUTDOWN`阶段都被关闭。 @matyhtf +- 优化内核代码。 @matyhtf + +## v6.0.0-beta + +### 新特性: +- 新增`Swoole\Thread\Map::find()`方法。 @matyhtf +- 新增`Swoole\Thread\ArrayList::find()`方法。 @matyhtf +- 新增`Swoole\Thread\ArrayList::offsetUnset()`方法。 @matyhtf +- 新增`Swoole\Process::getAffinity()`方法。 @matyhtf +- 新增`Swoole\Thread::setName()`方法。 @matyhtf +- 新增`Swoole\Thread::setAffinity()`方法。 @matyhtf +- 新增`Swoole\Thread::getAffinity()`方法。 @matyhtf +- 新增`Swoole\Thread::setPriority()`方法。 @matyhtf +- 新增`Swoole\Thread::getPriority()`方法。 @matyhtf +- 新增`Swoole\Thread::gettid()`方法。 +- 文件异步引擎`iouring`支持多线程轮询模式`IORING_SETUP_SQPOLL`。 @NathanFreeman +- 新增`iouring_workers`修改`iouring`线程数。 @NathanFreeman +- 新增`iouring_flags`支持修改`iouring`工作模式。 @NathanFreeman +- 增加`Swoole\Thead\Barrier`多线程同步屏障。@matyhtf +- 增加新的设置cookie的函数。 @matyhtf @NathanFreeman + +### Bug修复: +- 修复`Swoole\Http2\Request`动态属性问题。 @guandeng +- 修复`pgsql`协程客户端偶发资源不可用的问题。 @NathanFreeman +- 修复进程重启,没有重置相关参数导致503错误的问题。@matyhtf +- 修复开启`HTTP2`时,$request->server['request_method'] 与 $request->getMethod() 的结果不一致。 @matyhtf +- 修复上传文件时,不正确的`content-type`。 @matyhtf +- 修复`http2`协程客户端的代码错误。 @matyhtf +- 修复`Swoole\Server`缺少属性`worker_id`的问题。 @cjavad +- 修复`config.m4`有关`brotli`错误的问题。 @fundawang +- 修复 多线程下`Swoole\Http\Response::create`无效。 @matyhtf +- 修复`macos`环境下编译错误。 @matyhtf +- 修复线程无法安全退出的问题。 @matyhtf +- 修复多线程模式下,`Swoole\Http\Response`返回响应时间的静态变量没有各个线程各自生成一份的问题。 @matyhtf @NathanFreeman + +### 内核优化: +- 升级CI测试的oracle数据库版本。 @gvenzl +- 重构优化`swoole`底层相关代码。 @matyhtf +- 优化底层`sendfile`的相关逻辑。 @matyhtf +- 优化参数解析。 @matyhtf +- `config.m4`中用`AC_DEFINE_UNQUOTED`替换`PHP_DEF_HAVE`。 @petk +- 优化多线程模式下,server的`heartbeat`,`shutdown`和`stop`的相关逻辑。 @matyhtf +- 优化`glibc`版本高于2.17时,不需要链接`librt`。 @matyhtf +- 加强`http`客户端可以接受重复的请求头。 @matyhtf +- 优化`Swoole\Http\Response::write()`。 @matyhtf +- `Swoole\Http\Response::write()`现在可以发送`http2`协议。 @matyhtf +- 兼容`PHP8.4`。 @matyhtf @NathanFreeman +- 增加底层`socket`异步写入的能力。 @matyhtf +- 优化`Swoole\Http\Response`。 @NathanFreeman +- 优化底层错误信息。 @matyhtf +- 多线程模式下,支持共享php原生`socket`。 @matyhtf +- 优化静态文件服务,修复静态文件路径错误问题。 @matyhtf + +### 废弃: +- 移除`Swoole\Coroutine\System::fread()`, `Swoole\Coroutine\System::fwrite()`和`Swoole\Coroutine\System::fgets()`方法 + +## v6.0.0-alpha + ### 新特性 - `Swoole`支持多线程模式,当`php`是`zts`模式,编译`Swoole`时开启`--enable-swoole-thread`时,就能使用多线程模式。 - 新增线程管理类`Swoole\Thread`。 @matyhtf