【问题标题】:Lazy JSON encoding惰性 JSON 编码
【发布时间】:2014-08-11 19:29:57
【问题描述】:

考虑以下几点:

z = [{"x" => 5}, 2, 3].lazy.map{ |i| i}
#=> #<Enumerator::Lazy: #<Enumerator::Lazy: [{"x"=>5}, 2, 3]>:map>
z.first
#=> {"x"=>5}

当我尝试将z 转换为 JSON 时,我得到以下意外结果:

z.to_json
#=> "\"#<Enumerator::Lazy:0x00000001cb0448>\""

为什么to_json 不枚举这个惰性枚举器?

【问题讨论】:

  • to_json 应该请求什么?
  • 集合中的每个项目。
  • 不,它不要求每个项目。
  • 对不起,我的评论有误。懒惰是无关紧要的(除了它在内部将接收器转换为枚举器的事实)。真正的答案是:因为z 是一个枚举数。
  • 也许是因为(1..Float::INFINITY) 之类的东西可能存在问题,但我同意我希望to_json 只是迭代所有内容。您可以使用 to_a.to_json 而不是仅使用 .to_json 强制它。

标签: ruby lazy-evaluation


【解决方案1】:

to_json 不处理枚举数。它只转储它的字符串表示法:

> [].to_enum.to_json
=> "\"#<Enumerator:0x00000002503190>\""

您需要先将您的枚举数转换为数组:

> z.to_a.to_json
=> "[{\"x\":5},2,3]"

为了进一步说明,数组有自己的生成器模块:

> [].method(:to_json).owner
=> JSON::Ext::Generator::GeneratorMethods::Array

而枚举器只有默认值:

> [].to_enum.method(:to_json).owner
=> JSON::Ext::Generator::GeneratorMethods::Object

【讨论】:

  • to_a 有效,但这是我试图避免的。考虑一个流式 JSON 编码器:github.com/brianmario/yajl-ruby。我想避免将整个数组放在内存中,并在通过套接字流式传输结果时逐步编码 json。
  • 不幸的是yajl 具有转储枚举器的字符串表示法的相同行为。
  • 即使在 Rails 的 ActiveSupport 中,枚举器(可枚举的)也会先转换为数组。请参阅 active_support/core_ext/object/json.rbactive_support/json/encoding.rb。你可以使用require 'active_support'; ActiveSupport::JSON.encode(enumerator)
【解决方案2】:

这里有一篇很棒的博客文章详细介绍了如何进行惰性 json 编码。它需要猴子补丁,所以并不理想,但它简洁地涵盖了主题:

http://collectiveidea.com/blog/archives/2015/03/13/optimizing-rails-for-memory-usage-part-4-lazy-json-generation-and-final-thoughts/

猴子补丁代码:

https://gist.github.com/brianhempel/56823fb777fb567b676a

【讨论】:

    【解决方案3】:

    对于那些寻求将巨大对象写入json文件但因to_json而崩溃的人,请改用此方法:
    JSON.dump(arr_or_hash, File.open('my.json', 'w'))
    /p>

    如果您只想要 json 字符串:
    JSON.generate(arr_or_hash)

    【讨论】:

      猜你喜欢
      • 2014-09-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多