In general, what are the advantages and disadvantages of using an OpenStruct as compared to a Struct? What type of general use-cases would fit each of these?
UPDATE:
As of Ruby 2.4.1 OpenStruct and Struct are much closer in speed. See https://stackoverflow.com/a/43987844/128421
PREVIOUSLY:
For completeness: Struct vs. Class vs. Hash vs. OpenStruct
Running similar code as burtlo's, on Ruby 1.9.2, (1 of 4 cores x86_64, 8GB RAM) [table edited to align columns]:
creating 1 Mio Structs : 1.43 sec , 219 MB / 90MB (virt/res) creating 1 Mio Class instances : 1.43 sec , 219 MB / 90MB (virt/res) creating 1 Mio Hashes : 4.46 sec , 493 MB / 364MB (virt/res) creating 1 Mio OpenStructs : 415.13 sec , 2464 MB / 2.3GB (virt/res) # ~100x slower than Hashes creating 100K OpenStructs : 10.96 sec , 369 MB / 242MB (virt/res)
OpenStructs are sloooooow and memory intensive , and don't scale well for large data sets
Creating 1 Mio OpenStructs is ~100x slower than creating 1 Mio Hashes.
start = Time.now
collection = (1..10**6).collect do |i|
{:name => "User" , :age => 21}
end; 1
stop = Time.now
puts "#{stop - start} seconds elapsed"
Other benchmark:
require 'benchmark'
require 'ostruct'
REP = 100000
User = Struct.new(:name, :age)
USER = "User".freeze
AGE = 21
HASH = {:name => USER, :age => AGE}.freeze
Benchmark.bm 20 do |x|
x.report 'OpenStruct slow' do
REP.times do |index|
OpenStruct.new(:name => "User", :age => 21)
end
end
x.report 'OpenStruct fast' do
REP.times do |index|
OpenStruct.new(HASH)
end
end
x.report 'Struct slow' do
REP.times do |index|
User.new("User", 21)
end
end
x.report 'Struct fast' do
REP.times do |index|
User.new(USER, AGE)
end
end
end
For the impatient who wants to get an idea of the benchmark results, without running them themselves, here is the output of the code above (on an MB Pro 2.4GHz i7)
user system total real
OpenStruct slow 4.430000 0.250000 4.680000 ( 4.683851)
OpenStruct fast 4.380000 0.270000 4.650000 ( 4.649809)
Struct slow 0.090000 0.000000 0.090000 ( 0.094136)
Struct fast 0.080000 0.000000 0.080000 ( 0.078940)
Not actually an answer to the question, but a very important consideration if you care about performance. Please notice that every time you create an OpenStruct
the operation clears the method cache, which means your application will perform slower. The slowness or not of OpenStruct
is not just about how it works by itself, but the implications that using them bring to the whole application: https://github.com/charliesome/charlie.bz/blob/master/posts/things-that-clear-rubys-method-cache.md#openstructs