我需要在平面文件中存储多维数据关联数组,以便进行缓存。我可能偶尔会遇到需要将其转换为JSON以在我的web应用程序中使用,但绝大多数情况下,我将直接在PHP中使用数组。

在这个文本文件中将数组存储为JSON还是PHP序列化数组更有效?我查看了一下,似乎在最新版本的PHP(5.3)中,json_decode实际上比反序列化更快。

我目前倾向于将数组存储为JSON,因为我觉得如果有必要的话,它更容易被人阅读,它可以在PHP和JavaScript中使用,而且从我所读到的,它甚至可能更快地解码(虽然不确定编码)。

有人知道有什么陷阱吗?有人有好的基准来显示这两种方法的性能优势吗?


当前回答

我也做了一个小的基准测试。结果是一样的。但是我需要解码性能。我注意到,就像上面几个人说的,unserialize比json_decode快。反序列化大约占用json_decode时间的60-70%。所以结论很简单: 当需要编码时的性能时,使用json_encode,当需要解码时的性能时,使用unserialize。因为你不能合并这两个功能,你必须做出选择,你需要更多的性能。

我在pseudo中的基准:

用一些随机键和值定义数组$arr 对于x < 100;x + +;序列化和json_encode $arr的array_rand 对于y < 1000;y + +;Json_decode json编码的string - calc时间 对于y < 1000;y + +;取消序列化的string - calc时间 回声更快的结果

平均而言:unserialize赢得了96次胜过json_decode的4次。平均约1.5ms超过2.5ms。

其他回答

Y刚刚测试了serialized和json的encode和decode,加上它将把字符串存储的大小。

JSON encoded in 0.067085981369 seconds. Size (1277772)
PHP serialized in 0.12110209465 seconds. Size (1955548)
JSON decode in 0.22470498085 seconds
PHP serialized in 0.211947917938 seconds
json_encode() was roughly 80.52% faster than serialize()
unserialize() was roughly 6.02% faster than json_decode()
JSON string was roughly 53.04% smaller than Serialized string

我们可以得出结论,JSON编码更快,结果字符串更小,但unserialize解码字符串更快。

您可能还会对https://github.com/phadej/igbinary感兴趣——它为PHP提供了一个不同的序列化“引擎”。

我的随机/任意的“性能”数据,使用PHP 5.3.5在64位平台上显示:

JSON:

JSON编码在2.180496931076秒 JSON解码在9.8368630409241秒 serialized "String" size: 13993

原生PHP:

PHP在2.9125759601593秒内序列化 PHP在6.4348418712616秒内反序列化 序列化的“字符串”大小:20769

Igbinary:

winigbinary在1.6099879741669秒内序列化 winigbinary在4.7737920284271秒内未序列化 WIN序列化的“字符串”大小:4467

因此,igbinary_serialize()和igbinary_unserialize()更快,使用更少的磁盘空间。

我使用fillArray(0,3)代码,但使数组键更长的字符串。

igbinary可以存储与PHP原生序列化相同的数据类型(所以对象等没有问题),如果你愿意,你可以告诉PHP5.3使用它来进行会话处理。

参见http://ilia.ws/files/zendcon_2010_hidden_features.pdf -特别是幻灯片14/15/16

真是个不错的话题,在看了几个答案后,我想分享我在这个问题上的实验。

我有一个用例,几乎每次与数据库对话时都需要查询一些“巨大的”表(不要问为什么,只是一个事实)。数据库缓存系统是不合适的,因为它不会缓存不同的请求,所以我想到了php缓存系统。

我尝试了apcu,但它不符合需求,内存在这种情况下不够可靠。下一步是通过序列化将缓存到文件中。

表有14355个条目,有18列,这些是我的测试和读取序列化缓存的统计:

JSON:

正如大家所说,json_encode/json_decode的主要不便之处在于它将所有内容转换为StdClass实例(或对象)。如果你需要循环它,你可能会把它转换成一个数组,是的,这会增加转换时间

平均时间:780.2 ms;内存使用:41.5MB;缓存文件大小:3.8MB

Msgpack

@hutch提到了msgpack。漂亮的网站。让我们试一试,好吗?

平均时间:497 ms;内存使用:32MB;缓存文件大小:2.8MB

这样好多了,但需要一个新的扩展;编译有时害怕的人…

IgBinary

@GingerDog提到了igbinary。注意,我设置了igbinary.compact_strings= off,因为我更关心读取性能而不是文件大小。

平均时间:411.4 ms;内存使用:36.75MB;缓存文件大小:3.3MB

比味精包装好。不过,这个也需要编译。

系列化/非系列化

平均时间:477.2 ms;内存使用:36.25MB;缓存文件大小:5.9MB

比JSON更好的性能,数组越大,json_decode就越慢,但你已经知道了。

这些外部扩展缩小了文件大小,在纸上看起来很棒。数字不会说谎。如果您得到的结果与使用标准PHP函数得到的结果几乎相同,那么编译扩展还有什么意义呢?

我们还可以推断出,根据你的需求,你会选择与别人不同的东西:

IgBinary真的很好,比MsgPack执行得更好 Msgpack更擅长压缩数据(注意,我没有尝试igbinary 紧凑。字符串选项)。 不想编译?使用标准。

就是这样,另一个序列化方法的比较,帮助您选择一个!

*使用PHPUnit 3.7.31测试,php 5.5.10 -仅使用标准硬盘和旧双核CPU解码- 10个相同用例测试的平均数字,您的统计数据可能不同

首先,我修改了脚本,做了更多的基准测试(也做了1000次而不是1次):

<?php

ini_set('display_errors', 1);
error_reporting(E_ALL);

// Make a big, honkin test array
// You may need to adjust this depth to avoid memory limit errors
$testArray = fillArray(0, 5);

$totalJsonTime = 0;
$totalSerializeTime = 0;
$totalJsonWins = 0;

for ($i = 0; $i < 1000; $i++) {
    // Time json encoding
    $start = microtime(true);
    $json = json_encode($testArray);
    $jsonTime = microtime(true) - $start;
    $totalJsonTime += $jsonTime;

    // Time serialization
    $start = microtime(true);
    $serial = serialize($testArray);
    $serializeTime = microtime(true) - $start;
    $totalSerializeTime += $serializeTime;

    if ($jsonTime < $serializeTime) {
        $totalJsonWins++;
    }
}

$totalSerializeWins = 1000 - $totalJsonWins;

// Compare them
if ($totalJsonTime < $totalSerializeTime) {
    printf("json_encode() (wins: $totalJsonWins) was roughly %01.2f%% faster than serialize()\n", ($totalSerializeTime / $totalJsonTime - 1) * 100);
} else {
    printf("serialize() (wins: $totalSerializeWins) was roughly %01.2f%% faster than json_encode()\n", ($totalJsonTime / $totalSerializeTime - 1) * 100);
}

$totalJsonTime = 0;
$totalJson2Time = 0;
$totalSerializeTime = 0;
$totalJsonWins = 0;

for ($i = 0; $i < 1000; $i++) {
    // Time json decoding
    $start = microtime(true);
    $orig = json_decode($json, true);
    $jsonTime = microtime(true) - $start;
    $totalJsonTime += $jsonTime;

    $start = microtime(true);
    $origObj = json_decode($json);
    $jsonTime2 = microtime(true) - $start;
    $totalJson2Time += $jsonTime2;

    // Time serialization
    $start = microtime(true);
    $unserial = unserialize($serial);
    $serializeTime = microtime(true) - $start;
    $totalSerializeTime += $serializeTime;

    if ($jsonTime < $serializeTime) {
        $totalJsonWins++;
    }
}

$totalSerializeWins = 1000 - $totalJsonWins;


// Compare them
if ($totalJsonTime < $totalSerializeTime) {
    printf("json_decode() was roughly %01.2f%% faster than unserialize()\n", ($totalSerializeTime / $totalJsonTime - 1) * 100);
} else {
    printf("unserialize() (wins: $totalSerializeWins) was roughly %01.2f%% faster than json_decode()\n", ($totalJsonTime / $totalSerializeTime - 1) * 100);
}

// Compare them
if ($totalJson2Time < $totalSerializeTime) {
    printf("json_decode() was roughly %01.2f%% faster than unserialize()\n", ($totalSerializeTime / $totalJson2Time - 1) * 100);
} else {
    printf("unserialize() (wins: $totalSerializeWins) was roughly %01.2f%% faster than array json_decode()\n", ($totalJson2Time / $totalSerializeTime - 1) * 100);
}

function fillArray( $depth, $max ) {
    static $seed;
    if (is_null($seed)) {
        $seed = array('a', 2, 'c', 4, 'e', 6, 'g', 8, 'i', 10);
    }
    if ($depth < $max) {
        $node = array();
        foreach ($seed as $key) {
            $node[$key] = fillArray($depth + 1, $max);
        }
        return $node;
    }
    return 'empty';
}

我使用PHP 7的这个版本:

PHP 7.0.14 (cli)(已构建:2017年1月18日19:13:23)(NTS)版权所有(c) PHP Group Zend Engine v3.0.0,版权所有(c) 1998-2016 Zend技术 与Zend OPcache v7.0.14,版权(c) 1999-2016,由Zend Technologies

我的结果是:

Serialize()(胜:999)比json_encode()快大约10.98% Unserialize()(胜:987)大约比json_decode()快33.26% Unserialize()(胜:987)大约比array快48.35% json_decode ()

显然,序列化/反序列化是最快的方法,而json_encode/decode是最可移植的方法。

如果您考虑这样一个场景:您读/写序列化数据的次数是向非php系统发送数据或从非php系统接收数据的次数的10倍或更多,那么就时间而言,最好还是使用序列化/反序列化,并在序列化之前使用json_encode或json_decode。

我曾经写过一篇关于这个主题的博文:“缓存一个大数组:JSON,序列化还是var_export?”在这篇文章中,我们展示了序列化是大小数组的最佳选择。对于非常大的数组(> 70MB), JSON是更好的选择。