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

mwa*_*way 10 ruby serialization ruby-on-rails marshalling deep-copy

我知道序列化一个对象(据我所知)是有效深度复制一个对象的唯一方法(只要它不像有状态那样IO),但是这种方法比另一种更有效吗?

例如,因为我正在使用Rails,我总是可以使用ActiveSupport::JSON,to_xml- 从我可以告诉编组的对象是最常被接受的方法之一.我希望编组可能是最有效的,因为它是一个Ruby内部,但我错过了什么?

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

Eva*_*Pon 21

我想知道同样的事情,所以我对几种不同的技术进行了基准测试.我主要关注数组和哈希 - 我没有测试任何复杂的对象.也许不出所料,自定义深度克隆实现被证明是最快的.如果您正在寻找快速简便的实施方案,那么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
Run Code Online (Sandbox Code Playgroud)

结果是:

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)
Run Code Online (Sandbox Code Playgroud)