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)
-但我不确定它是否会有更好的性能。