Swoole 4.5.6 支持零拷貝 JSON 或 PHP 反序列化

在最新的4.5.6開發分支中,底層增長了2個特殊的函數:php

  • swoole_substr_json_decode
  • swoole_substr_unserialize

這裏爲何要增長這兩個函數呢?有這樣一種場景。使用Swoole\Server實現RPC服務,在EOF協議或長度協議通訊方式下,一個包可能有3部分組成。shell

$packet = $header + $body + $footer

一般$header$footer比較小,而$body比較大,$body可能會使用JSONPHP序列化格式。若是要解析$body數據,那麼就須要先進行substr獲得$body的字符串格式數據,再進行json_decodeunserialize操做。json

這會引發一次內存拷貝,$body_str = substr($packet, $header_length)的過程會建立一個臨時字符串變量,再反序列化操做$body = json_decode($body_str)以後,這個變量就會被釋放。segmentfault

// 先進行 substr,這時會產生內存拷貝,從 $packet 複製數據到 $body_str
$body_str = substr($packet, 4, strlen($packet) - 4 - 2);
// 反序列化以後 $body_str 這塊內存再也不使用,會在函數退出時釋放
$body = json_decode($body_str, true);

使用新增的兩個函數就能夠將substr反序列化操做合二爲一。減小一次內存拷貝,從而提升性能。swoole

$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_unserializesubstr + unserialize相比,性能提高了12%dom

htf@htf-ThinkPad-T470p:~/workspace/debug$ php s.php
cost: 2.2559139728546
htf@htf-ThinkPad-T470p:~/workspace/debug$ php s.php
cost: 1.9821600914001

Swoole官方

相關文章
相關標籤/搜索