为什么禁用GC时XML解析Ruby代码运行较慢?
我有一段代码,使用为什么禁用GC时XML解析Ruby代码运行较慢?,ruby,performance,garbage-collection,Ruby,Performance,Garbage Collection,我有一段代码,使用libxmlrubygem解析500 MB的XML文件。令我惊讶的是,这段代码在禁用GC的情况下运行得更慢,这似乎违反了直觉。原因可能是什么?我有足够的可用内存,系统没有交换 require 'xml' #GC.disable @reader = XML::Reader.file('books.xml', :options => XML::Parser::Options::NOBLANKS) @reader.read @reader.read while @re
libxmlruby
gem解析500 MB的XML文件。令我惊讶的是,这段代码在禁用GC的情况下运行得更慢,这似乎违反了直觉。原因可能是什么?我有足够的可用内存,系统没有交换
require 'xml'
#GC.disable
@reader = XML::Reader.file('books.xml', :options => XML::Parser::Options::NOBLANKS)
@reader.read
@reader.read
while @reader.name == 'book'
book_id = @reader.get_attribute('id')
@reader.read
until @reader.name == 'book' && @reader.node_type == XML::Reader::TYPE_END_ELEMENT
case @reader.name
when 'author'
author = @reader.read_string
when 'title'
title = @reader.read_string
when 'genre'
genre = @reader.read_string
when 'price'
price = @reader.read_string
when 'publish_date'
publish_date = @reader.read_string
when 'description'
description = @reader.read_string
end
@reader.next
end
@reader.read
end
@reader.close
以下是我得到的结果:
ruby gc on gc off
2.2.0 16.93s 18.81s
2.1.5 16.22s 18.58s
2.0.0 17.63s 17.99s
为什么要禁用垃圾收集器?我在书中读到Ruby的速度很慢,主要是因为程序员不考虑内存消耗,这使得垃圾收集器占用了大量的执行时间。因此,只要系统不进行交换,关闭GC就会立即加快速度(当然是以内存使用为代价的)
我想看看我的XML解析模块是否可以改进,所以我开始通过禁用GC来尝试它,这就导致了这个问题。我期望在禁用GC的情况下有一个显著的加速,但是我得到了相反的结果。我知道差别不大,但这对我来说还是很奇怪
libxml-ruby
gem在引擎盖下使用本机Clibxml
实现——这可能是原因吗
我使用的文件是从一些Microsoft文档下载的手动乘法books.xml
sample:
<catalog>
<book id="bk101">
<author>John Doe</author>
<title>XML for dummies</title>
<genre>Computer</genre>
<price>44.95</price>
<publish_date>2000-10-01</publish_date>
<description>Some description</description>
</book>
....
</catalog>
无名氏
傻瓜的XML
电脑类
44.95
2000-10-01
一些描述
....
我的设置:OS X Yosemite,Intel Core i5 2.6 GHz,16GB内存
谢谢您的建议。您忘记了操作系统-您在MRI进程中禁用了GC,但无法控制linux/unix内核及其如何为MRI应用程序分配内存 事实上,我相信禁用GC会大大削弱应用程序的行为,使程序可能需要不断地从内核请求更多的RAM。这可能会涉及内核中的某种形式的开销,因为它会将交换或内存分配给您 您的源数据是一个500 mb的xml文件,您正在逐节点将其读取到MRI程序的内存占用中。你的核磁共振成像过程在完成处理时可能会消耗数GB的数据;在每次迭代之后,主读取块中的值都不会被丢弃——它们只是挂在内存中,只有在应用程序退出并将内存返回到操作系统时才会被最终清除 GC已到位以管理这一点;它旨在防止应用程序从内核请求额外内存,除非它绝对需要它,并允许应用程序在合理分配给它的内存中“足够好”地运行
因此,我并不真的感到惊讶,你看到GC被禁用会减速。在基准测试过程中,你的盒子的平均负载和交换使用率是最能说明问题的。@engineersmnky如果他问的是如何让它更快,那么它就属于这里,而不是代码审查。如果他需要所有方面的帮助,应该去那里。@engineersmnky“原因可能是什么?我有足够的可用内存,并且系统没有交换。”@engineersmnky请参阅下面的部分,其中说“我需要有关代码任何或所有方面的反馈吗?”。OP不需要这种反馈。@engineersmnky与代码审查迁移建议中经常提到的相反,特定的代码改进绝对是关于堆栈溢出的主题。在任何情况下,正如我所能说的,OP不是在要求性能调整,而是在问一个特定的问题,为什么垃圾收集器在这种情况下表现出与预期相反的行为。感谢您对OS分配开销的建议。考虑到这一点,我会做一些额外的基准测试。想必你是对的。我可以看到,这个过程不断地以小增量分配越来越多的内存。为了证明你的观点,我寻找了一种在开始时预先分配大量内存的方法(比如Java中的
-Xmx
开关),这样在执行过程中就不必花费任何时间。但显然这在Ruby中是不可能的。