在Ruby中深度复制对象的最有效方法是什么? [英] What's the most efficient way to deep copy an object in 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::JSON
,to_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?
编辑:请注意,我已经介绍了它的实现-我不想替换现有的浅表复制方法(例如dup
和clone
),所以我只是最终可能会添加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屋!