Swoole 4.5.6 支持零拷贝 JSON 或 PHP 反序列化
source link: https://segmentfault.com/a/1190000037570031
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
在最新的 4.5.6
开发分支中,底层增加了 2
个特殊的函数:
swoole_substr_json_decode swoole_substr_unserialize
这里为什么要增加这两个函数呢?有这样一种场景。使用 Swoole\Server
实现 RPC
服务,在 EOF
协议或长度协议通信方式下,一个包可能有 3
部分组成。
$packet = $header + $body + $footer
通常 $header
和 $footer
比较小,而 $body
比较大, $body
可能会使用 JSON
或 PHP
序列化格式。如果要解析 $body
数据,那么就需要先进行 substr
得到 $body
的字符串格式数据,再进行 json_decode
和 unserialize
操作。
这会引起一次内存拷贝, $body_str = substr($packet, $header_length)
的过程会创建一个临时字符串变量,再反序列化操作 $body = json_decode($body_str)
之后,这个变量就会被释放。
// 先进行 substr,这时会产生内存拷贝,从 $packet 复制数据到 $body_str $body_str = substr($packet, 4, strlen($packet) - 4 - 2); // 反序列化之后 $body_str 这块内存不再使用,会在函数退出时释放 $body = json_decode($body_str, true);
使用新增的两个函数就可以将 substr
和 反序列化
操作合二为一。减少一次内存拷贝,从而提高性能。
$body = swoole_substr_json_decode($packet, $header_length); $body = swoole_substr_unserialize($packet, $header_length);
压测
<?php error_reporting(E_ALL); $a['hello'] = base64_encode(random_bytes(1000)); $a['world'] = 'hello'; $a['int'] = rand(1, 999999); $a['list'] = ['a,', 'b', 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx']; $val = serialize($a); $str = pack('N', strlen($val)).$val."rn"; $n = 100000; $s = microtime(true); while($n--) { $l = strlen($str) - 6; // var_dump(unserialize(substr($str, 4, $l))); var_dump(swoole_substr_unserialize($str, 4, $l)); } echo "cost: ".(microtime(true)-$s)."n";
使用 swoole_substr_unserialize
与 substr + unserialize
相比,性能提升了 12%
htf@htf-ThinkPad-T470p:~/workspace/debug$ php s.php cost: 2.2559139728546 htf@htf-ThinkPad-T470p:~/workspace/debug$ php s.php cost: 1.9821600914001
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK