在Ruby中深度复制对象的最有效方法是什么? [英] What's the most efficient way to deep copy an object in Ruby?

查看:127
本文介绍了在Ruby中深度复制对象的最有效方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I know that serializing an object is (to my knowledge) the only way to effectively deep-copy an object (as long as it isn't stateful like IO and whatnot), but is one way particularly more efficient than another?

例如,由于我使用的是Rails,因此我总是可以使用ActiveSupport::JSONto_xml-从我可以看出,将对象编组是执行此操作的最常用方法之一.我希望封送处理可能是其中最有效的一种,因为它是Ruby内部的,但是我有什么遗漏的吗?

For example, since I'm using Rails, I could always use ActiveSupport::JSON, to_xml - and from what I can tell marshalling the object is one of the most accepted ways to do this. I'd expect that marshalling is probably the most efficient of these since it's a Ruby internal, but am I missing anything?

编辑:请注意,我已经介绍了它的实现-我不想替换现有的浅表复制方法(例如dupclone),所以我只是最终可能会添加Object::deep_copy,其结果是上述方法中开销最低的任何一种方法(或您提出的任何建议).

Edit: note that its implementation is something I already have covered - I don't want to replace existing shallow copy methods (like dup and clone), so I'll just end up likely adding Object::deep_copy, the result of which being whichever of the above methods (or any suggestions you have :) that has the least overhead.

推荐答案

我想知道同一件事,所以我相互比较了一些不同的技术.我主要关心数组和哈希-我没有测试任何复杂的对象.也许不足为奇的是,自定义深度克隆实现被证明是最快的.如果您正在寻找快速简便的实施方案,那么元帅似乎是您的理想之选.

I was wondering the same thing, so I benchmarked a few different techniques against each other. I was primarily concerned with Arrays and Hashes - I didn't test any complex objects. Perhaps unsurprisingly, a custom deep-clone implementation proved to be the fastest. If you are looking for quick and easy implementation, Marshal appears to be the way to go.

我还用Rails 3.0.7(未在下面显示)对XML解决方案进行了基准测试.仅进行1000次迭代,速度就慢得多,大约10秒(对于基准测试,下面的所有解决方案都运行了10,000次).

I also benchmarked an XML solution with Rails 3.0.7, not shown below. It was much, much slower, ~10 seconds for only 1000 iterations (the solutions below all ran 10,000 times for the benchmark).

关于我的JSON解决方案的两点说明.首先,我使用了C版本1.4.3.其次,由于符号将转换为字符串,因此它实际上无法100%正常工作.

Two notes regarding my JSON solution. First, I used the C variant, version 1.4.3. Second, it doesn't actually work 100%, as symbols will be converted to Strings.

这都是使用ruby 1.9.2p180运行的.

This was all run with 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中深度复制对象的最有效方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆