JRuby 9.2和Rails 4.2
我一直在读/转储大型json对象,100+mb文件,这些文件通常会挂起几分钟,然后在写出来时内存不足。
我注意到它在使用to_json时特别发生。下面是一个4MB文件,因此它实际上完成了:

pry(main)> f = File.open('nvdcve-1.0-recent.json'){|f| JSON.load(f) }
pry(main)> puts Benchmark.measure{ JSON.dump(f) }
  0.230000   0.010000   0.240000 (  0.081894)
=> nil
pry(main)> puts Benchmark.measure{ f.to_json }
  1.020000   0.020000   1.040000 (  0.820851)
=> nil

问题的根源在于activesupport正在覆盖一堆东西:
pry(main)> f.method(:to_json)
=> #<Method: Hash#to_json(to_json_with_active_support_encoder)>
pry(main)> puts Benchmark.measure{ f.to_json_without_active_support_encoder }
  0.040000   0.000000   0.040000 (  0.035408)
pry(main)> puts Benchmark.measure{ f.to_json_with_active_support_encoder }
  1.170000   0.010000   1.180000 (  0.812674)

请看这里:https://apidock.com/rails/Object/to_json_with_active_support_encoder
那么,to_json与json gem的ActiveSupport::JSON.encode究竟有什么不同之处导致它的速度慢得多,即使是从json文件开始加载的不起眼的json文件也是如此?
如果我重写to_json而不使用activesupport变量,我会破坏rails的任何功能吗?

最佳答案

根据to the sourceactivesupport::json基本上只是json gem之上的一个附加层,它实际上完成了大部分繁重的工作。它主要做的是:
转义某些在某些浏览器中可能有问题的其他字符。

ESCAPED_CHARS = {
            "\u2028" => '\u2028',
            "\u2029" => '\u2029',
            ">"      => '\u003e',
            "<"      => '\u003c',
            "&"      => '\u0026',
            }

这些注释并没有说明有问题的浏览器是什么,这对于现代浏览器来说可能是完全没有问题的。
将对象强制转换为适当的json表示:
      # Convert an object into a "JSON-ready" representation composed of
      # primitives like Hash, Array, String, Numeric,
      # and +true+/+false+/+nil+.
      # Recursively calls #as_json to the object to recursively build a
      # fully JSON-ready object.
      #
      # This allows developers to implement #as_json without having to
      # worry about what base types of objects they are allowed to return
      # or having to remember to call #as_json recursively.
      #
      # Note: the +options+ hash passed to +object.to_json+ is only passed
      # to +object.as_json+, not any of this method's recursive +#as_json+
      # calls.
      def jsonify(value)
        case value
        when String
          EscapedString.new(value)
        when Numeric, NilClass, TrueClass, FalseClass
          value.as_json
        when Hash
          Hash[value.map { |k, v| [jsonify(k), jsonify(v)] }]
        when Array
          value.map { |v| jsonify(v) }
        else
          jsonify value.as_json
        end
      end

这可能是最重要的部分,因为#as_json对于模型如何将自己表示为json非常关键。它还处理强制转换日期和时间戳以及其他非原语(activesupport为它们提供#as_json方法)。去掉这个很可能会破坏很多东西。
根据您的用例,您也许可以从模型对象中手动创建ruby对象(数组、散列等),并使用JSON.generate(data)-但我不确定它是否会有更好的性能。

10-02 15:55