Swoole v4.6.0 版本公布了,同样也是 2021 年的首个版本更新。

作为一个 y 版本公布,此次更新也蕴含了不兼容的批改以及许多的新性能,上面就来看一看都有哪些改变?

向下不兼容改变

  1. v4.6.0 版本开始将不再反对 PHP7.1

PHP 官网对于 PHP7.1 的反对也早已在 2019 年底完结。

  1. Event::rshutdown() 标记为已弃用,请改用 Coroutine\run

在之前的版本中,如果在index.php中间接应用go创立协程

go(function () {    var_dump(Co\System::gethostbyname('www.baidu.com'));});

这样是失常的,然而在此版本中,就会收到废除正告

PHP Deprecated:  Swoole\Event::rshutdown(): Event::wait() in shutdown function is deprecated in Unknown on line 0

举荐应用Coroutine\run来代替这种形式:

Swoole\Coroutine\run(function () {    var_dump(Co\System::gethostbyname('www.baidu.com'));});Swoole\Coroutine\run(function () {    go(function () {        var_dump(Co\System::gethostbyname('www.baidu.com'));    });    go(function () {        var_dump(Co\System::gethostbyname('www.zhihu.com'));    });});
  1. 默认启用 Coroutine hook

应用了下面所说的Coroutine\run之后,也会迎来一个新的变更:默认启用 Coroutine hook,即主动设置SWOOLE_HOOK_ALL

use Swoole\Runtime;Swoole\Coroutine\run(function () {    $flags = Runtime::getHookFlags();    assert($flags === SWOOLE_HOOK_ALL);    var_dump($flags);});

当然也能够自行设置所须要的 flag

use Swoole\Runtime;Runtime::setHookFlags(SWOOLE_HOOK_TCP);Swoole\Coroutine\run(function () {    $flags = Runtime::getHookFlags();    assert($flags === SWOOLE_HOOK_TCP);    var_dump($flags);});
  1. 应用协程时禁用不平安性能,包含 pcntl_fork/pcntl_wait/pcntl_waitpid/pcntl_sigtimedwait
Swoole\Coroutine\run(function () {    $pid = pcntl_fork();    var_dump($pid);});

在此版本应用下面的示例代码,你将会失去一个 Warning 谬误

PHP Warning:  pcntl_fork() has been disabled for security reasons
  1. 移除了 session_id 的最大限度,不再反复

将 Server 的 session_idint24 改为了 int64 ,这样能够继续自增,永不反复。

之前的int24时,session_id大概能够到 1600 万就可能会呈现反复的问题。

新增 API & 加强

原生 curl 协程客户端 (SWOOLE_HOOK_NATIVE_CURL)

在这个版本中最大的变动莫过于反对了原生 curl 协程客户端,有什么用呢?

用过 SWOOLE_HOOK_CURL 的小伙伴应该晓得,有一些不反对的选项,同时还会因为局部 SDK 的不兼容导致一些谬误,例如:

PHP Notice:  Object of class Swoole\Curl\Handler could not be converted to intPHP Warning: curl_multi_add_handle() expects parameter 2 to be resource, object given

起因是 hook 后的 curl 不再是一个 resource 类型,而是 object 类型。

呈现这种问题也倡议分割 SDK 方批改代码,因为在 PHP8curl 不再是 resource 类型,而是 object 类型

以及常常应用的阿里云 OSS SDK 也是不反对SWOOLE_HOOK_CURL的,会遇到一些奇奇怪怪的

那么从 v4.6.0 版本开始就能够应用 SWOOLE_HOOK_NATIVE_CURL 代替 SWOOLE_HOOK_CURL,来解决以上提到的问题

应用SWOOLE_HOOK_NATIVE_CURL须要在编译 Swoole 扩大时减少 --enable-swoole-curl 编译参数,开启该选项后将主动设置 SWOOLE_HOOK_NATIVE_CURL,敞开 SWOOLE_HOOK_CURL,同时 SWOOLE_HOOK_ALL 也会蕴含 SWOOLE_HOOK_NATIVE_CURL

pecl 的 v4.6.0 版本临时没有减少这个选项,请应用手动编译开启,下个版本中会减少。

编译胜利后应用--ri查看信息,就能够看到curl-native

$ php --ri swoole | grep curlcurl-native => enabled

从上面的例子就能够看出两者的不同

Swoole\Runtime::setHookFlags(SWOOLE_HOOK_CURL);Swoole\Coroutine\run(function () {    $curl = curl_init();    var_dump(get_class($curl), (int) $curl);    //PHP Notice:  Object of class Swoole\Curl\Handler could not be converted to int    //string(19) "Swoole\Curl\Handler"    //int(1)});
Swoole\Coroutine\run(function () {    $curl = curl_init();    var_dump($curl, (int) $curl);    //resource(4) of type (Swoole-Coroutine-cURL Handle)    //int(4)});

SWOOLE_HOOK_SOCKETS

减少了对 ext-sockets 的协程化反对

const N = 8;$GLOBALS['time'] = [];$s = microtime(true);Swoole\Runtime::setHookFlags(SWOOLE_HOOK_SOCKETS);Swoole\Coroutine\run(function () {    $n = N;    while($n--) {        go(function() {            $s = microtime(true);            $domain = 'www.baidu.com';            $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);            socket_connect($sock, $domain, 80);            socket_write($sock, "GET / HTTP/1.0\r\nHost: $domain\r\nConnection: close\r\nKeep-Alive: off\r\n\r\n");            $html = '';            while(true) {                $data = socket_read($sock, 8192);                if ($data == '') {                    break;                }                $html .= $data;            }            socket_close($sock);            $GLOBALS['time'][] = microtime(true) - $s;        });    }});echo "Done\n";var_dump(microtime(true) - $s, array_sum($GLOBALS['time']) / 3);

反对 Server 事件回调函数传递对象格调的参数

默认不启用。通过设置 event_object 参数进行启用,以下事件回调将应用对象格调

  • onConnect
  • onReceive
  • onClose
  • onPacket
  • onPipeMessage
  • onWorkerError
  • onTask
  • onFinish

onConnect 为例,具体内容可参考文档 回调对象

$server->on('Connect', function (Swoole\Server $server, int $fd, int $reactorId) {    var_dump($fd);});$server->set([    'event_object' => true,]);$server->on('Connect', function (Swoole\Server $serv, Swoole\Server\Event $object) {    var_dump($object);});

反对反复 header

反对反复设置雷同 $key 的 HTTP 头,并且 $value 反对多种类型,如 arrayobjectintfloat,底层会进行 toString 转换,并且会移除开端的空格以及换行

$http = new Swoole\Http\Server('0.0.0.0', 9501);$http->on('request', function ($request, $response) {    $response->header('Test-Value', [        "a\r\n",        'd5678',        "e  \n ",        null,        5678,        3.1415926,    ]);    $response->header('Foo', new SplFileInfo('bar'));});$http->start();
$ curl -I http://127.0.0.1:9501HTTP/1.1 200 OKTest-Value: aTest-Value: d5678Test-Value: eTest-Value: 5678Test-Value: 3.1415926Foo: barServer: swoole-http-serverConnection: keep-aliveContent-Type: text/htmlDate: Wed, 06 Jan 2021 05:16:17 GMTContent-Length: 39

协程死锁检测

默认开启,能够通过在 Coroutine::set 中设置 enable_deadlock_check 进行敞开

在 EventLoop 终止后,如果存在协程死锁,底层会输入相干堆栈信息:

=================================================================== [FATAL ERROR]: all coroutines (count: 1) are asleep - deadlock!=================================================================== [Coroutine-2]--------------------------------------------------------------------#0  Swoole\Coroutine::printBackTrace() called at [@swoole-src/library/core/Coroutine/functions.php:74]#1  Swoole\Coroutine\deadlock_check()#2  curl_getinfo() called at [/mnt/c/code/php/hyperf-skeleton/vendor/aliyuncs/oss-sdk-php/src/OSS/Http/RequestCore.php:492]

更新日志

上面是残缺的更新日志

向下不兼容改变

  • 移除了session id的最大限度,不再反复 (#3879) (@matyhtf)
  • 应用协程时禁用不平安性能,包含pcntl_fork/pcntl_wait/pcntl_waitpid/pcntl_sigtimedwait (#3880) (@matyhtf)
  • 默认启用 coroutine hook (#3903) (@matyhtf)

移除

  • 不再反对 PHP7.1 (4a963df) (9de8d9e) (@matyhtf)

废除

  • Event::rshutdown() 标记为已弃用,请改用 Coroutine\run (#3881) (@matyhtf)

新增 API

  • 反对 setPriority/getPriority (#3876) (@matyhtf)
  • 反对 native-curl hook (#3863) (@matyhtf) (@huanghantao)
  • 反对 Server 事件回调函数传递对象格调的参数,默认不传递对象格调的参数 (#3888) (@matyhtf)
  • 反对 hook sockets 扩大 (#3898) (@matyhtf)
  • 反对反复 header (#3905) (@matyhtf)
  • 反对 SSL sni (#3908) (@matyhtf)
  • 反对 hook stdio (#3924) (@matyhtf)
  • 反对 stream_socket 的 capture_peer_cert 选项 (#3930) (@matyhtf)
  • 增加 Http\Request::create/parse/isCompleted (#3938) (@matyhtf)
  • 增加 Http\Response::isWritable (db56827) (@matyhtf)

加强

  • Server 的所有工夫精度都从 int 批改为 double (#3882) (@matyhtf)
  • 在 swoole_client_select 函数外面查看 poll 函数的 EINTR 状况 (#3909) (@shiguangqi)
  • 增加协程死锁检测 (#3911) (@matyhtf)
  • 反对应用 SWOOLE_BASE 模式在另一个过程中敞开连贯 (#3916) (@matyhtf)
  • 优化 Server master 过程与 worker 过程通信的性能,缩小内存拷贝 (#3910) (@huanghantao) (@matyhtf)

修复

  • 当 Coroutine\Channel 被敞开时,pop 出外面所有的数据 (960431d) (@matyhtf)
  • 修复应用 JIT 时的内存谬误 (#3907) (@twose)
  • 修复 port->set() dtls 编译谬误 (#3947) (@Yurunsoft)
  • 修复 connection_list 谬误 (#3948) (@sy-records)
  • 修复 ssl verify (#3954) (@matyhtf)
  • 修复 Table 递增和递加时不能革除所有列问题 (#3956) (@matyhtf) (@sy-records)
  • 修复应用 LibreSSL 2.7.5 编译失败 (#3962) (@matyhtf)
  • 修复未定义的常量 CURLOPT_HEADEROPT 和 CURLOPT_PROXYHEADER (swoole/library#77) (@sy-records)

内核

  • 默认状况下疏忽 SIGPIPE 信号 (9647678) (@matyhtf)
  • 反对同时运行 PHP 协程和 C 协程 (c94bfd8) (@matyhtf)
  • 增加 get_elapsed 测试 (#3961) (@luolaifa000)
  • 增加 get_init_msec 测试 (#3964) (@luffluo)