ruby-on-rails - 在 Ruby 中深度复制对象的最有效方法是什么?

标签 ruby-on-rails ruby serialization marshalling deep-copy

我知道序列化对象是(据我所知)有效深度复制对象的唯一方法(只要它不像 IO 之类的那样是有状态的),但它是一个比其他方式特别有效?

例如,由于我使用的是 Rails,所以我总是可以使用 ActiveSupport::JSONto_xml - 据我所知,编码对象是其中之一最被接受的方法来做到这一点。我希望编码可能是其中最有效的,因为它是 Ruby 内部的,但我是否遗漏了什么?

编辑:请注意,它的实现是我已经涵盖的内容 - 我不想替换现有的浅拷贝方法(如 dupclone),所以我最终可能会添加 Object::deep_copy,其结果是上述方法中的任何一个(或您的任何建议 :) 开销最少。

最佳答案

我也在想同样的事情,所以我将几种不同的技术相互进行了基准测试。我主要关注数组和散列——我没有测试任何复杂的对象。也许不足为奇,自定义深度克隆实现被证明是最快的。如果您正在寻找快速简便的实现方式,Marshal 似乎是您的不二之选。

我还使用 Rails 3.0.7 对 XML 解决方案进行了基准测试,下面未显示。它慢得多,只有 1000 次迭代大约 10 秒(下面的解决方案都运行了 10,000 次基准测试)。

关于我的 JSON 解决方案的两个注释。首先,我使用了 C 变体,版本 1.4.3。其次,它实际上并不是 100% 有效,因为符号将被转换为字符串。

这一切都是用 ruby​​ 1.9.2p180 运行的。

#!/usr/bin/env ruby
require 'benchmark'
require 'yaml'
require 'json/ext'
require 'msgpack'

def dc1(value)
  Marshal.load(Marshal.dump(value))
end

def dc2(value)
  YAML.load(YAML.dump(value))
end

def dc3(value)
  JSON.load(JSON.dump(value))
end

def dc4(value)
  if value.is_a?(Hash)
    result = value.clone
    value.each{|k, v| result[k] = dc4(v)}
    result
  elsif value.is_a?(Array)
    result = value.clone
    result.clear
    value.each{|v| result << dc4(v)}
    result
  else
    value
  end
end

def dc5(value)
  MessagePack.unpack(value.to_msgpack)
end

value = {'a' => {:x => [1, [nil, 'b'], {'a' => 1}]}, 'b' => ['z']}

Benchmark.bm do |x|
  iterations = 10000
  x.report {iterations.times {dc1(value)}}
  x.report {iterations.times {dc2(value)}}
  x.report {iterations.times {dc3(value)}}
  x.report {iterations.times {dc4(value)}}
  x.report {iterations.times {dc5(value)}}
end

结果:

user       system     total       real
0.230000   0.000000   0.230000 (  0.239257)  (Marshal)
3.240000   0.030000   3.270000 (  3.262255)  (YAML) 
0.590000   0.010000   0.600000 (  0.601693)  (JSON)
0.060000   0.000000   0.060000 (  0.067661)  (Custom)
0.090000   0.010000   0.100000 (  0.097705)  (MessagePack)

关于ruby-on-rails - 在 Ruby 中深度复制对象的最有效方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5643432/

相关文章:

ruby-on-rails - 如何使用Passenger 和Apache 设置我的RAILS_ENV?

ruby-on-rails - 将Rails与Oracle一起使用时,为什么会出现“无监听器”错误?

java - JettisonMappedXmlDriver 和 XStream 的 pretty-print

Json 日期被序列化为错误的格式

qt - 如何序列化自定义对象

ruby-on-rails - Rspec 命名空间 Controller 失败

ruby-on-rails - rails c 没有使用与 rails db 相同的数据库

ruby-on-rails - 分组时选择最大值的记录

ruby-on-rails - 如何设置不记名 token 参数以使用 Rswag UI 测试 Rails API

ruby - 如何读取 Rack 请求中的POST数据