【问题标题】:How to serialize large objects/arrays to JSON如何将大对象/数组序列化为 JSON
【发布时间】:2014-01-28 01:35:51
【问题描述】:

我的应用程序需要生成一个对象的 json,该对象具有数组类型的大型 data 属性。数组在收集 DB 输出时需要保留在内存中,并且只有在数组完成后才能确定某些属性。

复杂性:数组是基于数字的,必须在 json 输出中显示,因此直接json_encode() 不是一个选项。

为了在 RasPi 等低规格机器上实现这一点,我研究了减少内存消耗:

  1. 使用SPLFixedArray
  2. 使用stringpack()

这两种方法都解决了数组存储内存问题,但在 JSON 编码时都失败了。

我已经研究过实现JsonSerializable,但因为它强制用户返回结果,然后用 Json 编码,所以我回到了

public function jsonSerialize() {
    return $this->toArray();
}

有同样的内存问题。

zendframework/Component_ZendJson 看起来很有希望,因为它寻找具有toJson() 方法的对象,以提供自己的编码为string而不是object

我想知道是否有更好的选项不会出现内存问题?

【问题讨论】:

  • 我确信您所做的事情超出了我的想象,但 PHP 本身就有 json_encode。如果它不适用,那么我可以删除此评论 =)
  • 好收获。当然有一个原因我忘了说。真可惜。复杂性:数组是基于数字的,并且必须在 json 输出中显示,因此直接json_encode() 不是一个选项。
  • @MikeB:需要相反的方式-强制它为数组而不是对象。

标签: php arrays json zend-framework spl


【解决方案1】:

根据json.org

JSON 建立在两种结构之上:

  • 名称/值对的集合。在各种语言中,这被实现为对象、记录、结构、字典、哈希表、键控 列表或关联数组。
  • 值的有序列表。在大多数语言中,这被实现为数组、向量、列表或序列。

我不知道这是否存在内存问题,但请考虑以下代码:

<?php
// No declared index causes no index in JSON
$arr = array('dssdf','38904uj');
echo json_encode($arr).'<br><br>';
// ["dssdf","38904uj"]

// start array at 0 removes the index from JSON
$arr = array('0'=>'dssdf','1'=>'38904uj');
echo json_encode($arr).'<br><br>';
// ["dssdf","38904uj"]

// start array at 1 forces the index to show in JSON
$arr = array('1'=>'dssdf','2'=>'38904uj');
echo json_encode($arr).'<br><br>';
// {"1":"dssdf","2":"38904uj"}

// skip an index forces the index to show in JSON
$arr = array('0'=>'dssdf','1'=>'38904uj','3'=>'321as5d4');
echo json_encode($arr).'<br><br>';
// {"0":"dssdf","1":"38904uj","3":"321as5d4"}

// JSON_FORCE_OBJECT option forces indexes
$arr = array('0'=>'dssdf','1'=>'38904uj');
echo json_encode($arr, JSON_FORCE_OBJECT).'<br><br>';
// {"0":"dssdf","1":"38904uj"}
?>

【讨论】:

    【解决方案2】:

    在我的调查中,我研究了 5 种在内存中存储大型元组数组的不同方法,这里总结了它们的结果(以 50k 记录采样):

    1. 天真

      使用 array(array(), array()) 的 json_encode 导出 json 很简单

      内存:18.5MB(巨大
      时间:~100ms 构建和转储阵列(Windows PC)

    2. SPL 库

      这种方法将所有内容存储在嵌套的 SPLFixedArrays: SPLFixedArray[SPLFixedArray] 中。 JSON 导出是通过实现 toJson 方法扩展 Zend\Json\Encoder 完成的。

      内存:15.5MB(仍然很大
      时间:~1.3s,x10 慢

    3. SPL 库

      类似于 2,但不是内部的 SPLFixedArray 使用来自 PHP 的 pack() 函数的打包字符串。

      内存:3.5MB(小 5 倍
      时间:~1.3 秒,慢 10 倍 - 显然 pack() 与嵌套数组一样慢。

    4. SPL 库

      类似于 2,但不是内部的 SPLFixedArray,实际的元组只是作为顺序值写入根数组。

      内存:3.25MB(再次变小
      时间:~0.7 秒,仅慢 6 倍 - 我们这里有赢家吗?

    5. pack()

      类似于 3,但不是根 SPLFixedArray 使用 PHP 的 pack() 函数将所有内容打包成一个字符串。这显然需要关于各个数组的固定、相同结构的知识。

      内存:1.25MB(非常小 - 仅为原始内存的 1/12
      时间:~1.7s,x16 慢

    结论

    虽然 (5) 提供了最佳的内存利用率,但它也非常慢。出于我的目的,我选择了 (4),这大约是原始内存消耗的 20%,但是 - 当考虑 JSON 编码时 - 也慢了 5~6 倍。可接受的妥协。

    【讨论】:

    • 最好和最全面的答案之一。
    猜你喜欢
    • 2021-05-29
    • 1970-01-01
    • 2014-03-05
    • 2019-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多