为什么使用ruby比使用xpath更快地找到具有所需文本的节点?

时间:2018-04-27 15:32:33

标签: ruby xpath nokogiri benchmarking

最近我不得不检查html节点是否包含所需的文本。我很惊讶当我重构代码以使用xpath选择器时,它变得慢了10倍。有基准

的原始代码的简化版本
# has_keyword_benchmark.rb
require 'benchmark'
require 'nokogiri'

Doc = Nokogiri("
<div>
  <div>
    A
  </div>
  <p>
    <b>A</b>
  </p>
  <span>
    B
  </span>
</div>")

def has_keywords_with_xpath
  Doc.xpath('./*[contains(., "A")]').size > 0
end

def has_keywords_with_ruby
  Doc.text.include? 'A'
end

iterations = 10_000
Benchmark.bm(27) do |bm|
  bm.report('checking if has keywords with xpath') do
    iterations.times do
      has_keywords_with_xpath
    end
  end

  bm.report('checking if has keywords with ruby') do
    iterations.times do
      has_keywords_with_ruby
    end
  end
end

当我运行ruby has_keyword_benchmark.rb时,我得到了

                                  user     system      total        real
checking if has keywords with xpath  0.400000   0.020000   0.420000 (  0.428484)
checking if has keywords with ruby  0.020000   0.000000   0.020000 (  0.023773)

使用xpath直观地检查节点是否有某些文本应该更快,但事实并非如此。有人知道为什么吗?

1 个答案:

答案 0 :(得分:2)

通常,解析和编译XPath表达式比实际执行它需要更长的时间,即使在相当大的文档上也是如此。例如,对于Saxon,对1Mb源文档运行表达式count(//*[contains(., 'e')]),编译路径表达式需要200ms,而执行它需要大约18ms。

如果您的XPath API允许您编译一次XPath表达式然后重复执行它(或者如果它在后台缓存编译后的表达式),那么绝对值得利用该功能。

实际的XPath执行可能至少与手写的导航代码一样快,可能更快。这是导致开销的准备。