thi*_*ign 9 ruby memory parsing json yajl
我在Ruby中处理一个巨大的JSON文件时遇到了麻烦.我正在寻找的是一种逐个处理它的方法,而不会在内存中保留太多数据.
我认为yajl-ruby gem会做这项工作,但它会消耗我所有的记忆.我也看过Yajl :: FFI和JSON:流宝石,但有明确说明:
对于较大的文档,我们可以使用IO对象将其流式传输到解析器中.我们仍然需要解析对象的空间,但文档本身永远不会完全读入内存.
这是我用Yajl做的事情:
file_stream = File.open(file, "r")
json = Yajl::Parser.parse(file_stream)
json.each do |entry|
entry.do_something
end
file_stream.close
Run Code Online (Sandbox Code Playgroud)
内存使用量持续增加,直到进程被终止.
我不明白为什么Yajl会在内存中保留已处理的条目.我可以以某种方式释放它们,还是我误解了Yajl解析器的功能?
如果无法使用Yajl完成:有没有办法在Ruby中通过任何库?
json = Yajl :: Parser.parse(file_stream)
当您像这样调用Yajl :: Parser时,整个流将加载到内存中以创建数据结构.不要那样做.
Yajl提供了Parser#parse_chunk,Parser#on_parse_complete以及其他相关方法,使您能够在流上触发解析事件,而无需一次解析整个IO流.README 包含一个如何使用分块的示例.
README中给出的示例是:
或者假设您无法访问包含JSON数据的IO对象,而是一次只能访问它的块.没问题!
(假设我们在EventMachine :: Connection实例中)
Run Code Online (Sandbox Code Playgroud)def post_init @parser = Yajl::Parser.new(:symbolize_keys => true) end def object_parsed(obj) puts "Sometimes one pays most for the things one gets for nothing. - Albert Einstein" puts obj.inspect end def connection_completed # once a full JSON object has been parsed from the stream # object_parsed will be called, and passed the constructed object @parser.on_parse_complete = method(:object_parsed) end def receive_data(data) # continue passing chunks @parser << data end或者,如果您不需要对其进行流式传输,它只会在完成后从解析中返回构建的对象.注意:如果输入中将有多个JSON字符串,则必须指定一个块或回调,因为这是yajl-ruby将每个对象传递给您(调用者)的方式,因为它是从输入中解析出来的.
Run Code Online (Sandbox Code Playgroud)obj = Yajl::Parser.parse(str_or_io)
无论如何,您必须一次只解析一部分JSON数据.否则,您只是在内存中实例化一个巨大的Hash,这正是您描述的行为.
如果不知道您的数据是什么样的以及JSON对象是如何组成的,那么就不可能给出更详细的解释.因此,您的里程可能会有所不同.但是,这至少应该指向正确的方向.
| 归档时间: |
|
| 查看次数: |
4789 次 |
| 最近记录: |