Genel olarak, bir Yapıyla karşılaştırıldığında OpenStruct kullanmanın avantajları ve dezavantajları nelerdir? Bunların her birine ne tür genel kullanım durumları uygundur?
Genel olarak, bir Yapıyla karşılaştırıldığında OpenStruct kullanmanın avantajları ve dezavantajları nelerdir? Bunların her birine ne tür genel kullanım durumları uygundur?
Yanıtlar:
İle OpenStruct
, keyfi olarak özellikler oluşturabilirsiniz. Struct
Öte yandan, A'yı oluştururken tanımlanmış niteliklere sahip olmalıdır. Birinin diğerinin seçimi, daha sonra nitelik ekleyebilmeniz gerekip gerekmediğine dayanmalıdır.
Bunları düşünmenin yolu, bir taraftaki Hashes ile diğer taraftaki sınıflar arasındaki spektrumun orta zeminidir. Veriler arasında a'dan daha somut bir ilişki olduğunu ima ederler Hash
, ancak sınıfta olduğu gibi örnek yöntemlere sahip değildirler. Örneğin, bir işlev için bir grup seçenek bir karma içinde mantıklıdır; sadece gevşek ilişkilidirler. Bir işlevin ihtiyaç duyduğu bir ad, e-posta ve telefon numarası bir Struct
veya içinde birlikte paketlenebilir OpenStruct
. Bu ad, e-posta ve telefon numarası, adı hem "İlk Son" hem de "Son, İlk" biçiminde sağlamak için yöntemlere gereksinim duyuyorsa, bunu işlemek için bir sınıf oluşturmanız gerekir.
class Point < Struct.new(:x, :y); methods here; end
Point = Struct.new(:x, :y) { methods here }
. ( kaynak ) Tabii ki, { ... }
çok satırlı bir blok ( do ... end
) olarak yazılabilir ve bence tercih edilen yol budur.
Diğer kriter:
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
Kıyaslama sonuçları hakkında bir fikir edinmek isteyen sabırsızlar için, kendilerini çalıştırmadan, yukarıdaki kodun çıktısı (MB Pro 2.4GHz i7'de)
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)
GÜNCELLEME:
Ruby 2.4.1'den itibaren OpenStruct ve Struct hızlarına çok daha yakın. Bkz. Https://stackoverflow.com/a/43987844/128421
ÖNCEDEN:
Tamlık için: Struct - Class ve Hash vs. OpenStruct
Ruby 1.9.2'de burtlo's ile benzer kodu çalıştırıyor (4 çekirdekten 1 x86_64, 8GB RAM) [tablo sütunları hizalamak için düzenlendi]:
1 Mio Yapısı oluşturma: 1,43 sn, 219 MB / 90 MB (virt / res) 1 Mio Sınıfı örneği oluşturma: 1,43 sn, 219 MB / 90 MB (virt / res) 1 Mio Karması oluşturma: 4.46 sn, 493 MB / 364MB (virt / res) 1 Mio OpenStructs oluşturma: 415.13 sn, 2464 MB / 2.3 GB (virt / res) Hashes'ten ~ 100 kat daha yavaş 100K OpenStructs oluşturma: 10.96 sn, 369 MB / 242MB (virt / res)
OpenStructs olan sloooooow ve yoğun bellek ve büyük veri kümeleri için de ölçekli değil
1 Mio OpenStructs Oluşturma olduğu daha yavaş 100x 1 Mio oluşturarak karmaları .
start = Time.now
collection = (1..10**6).collect do |i|
{:name => "User" , :age => 21}
end; 1
stop = Time.now
puts "#{stop - start} seconds elapsed"
İkisi için kullanım durumları oldukça farklıdır.
Ruby 1.9'daki Struct sınıfını struct
C'deki bildirime eşdeğer olarak düşünebilirsiniz. Ruby'de Struct.new
bir alan adları kümesini bağımsız değişken olarak alır ve yeni bir Sınıf döndürür. Benzer şekilde, C'de bir struct
bildirim bir dizi alanı alır ve programcının yeni karmaşık türü tıpkı herhangi bir yerleşik türde olduğu gibi kullanmasına izin verir.
Yakut:
Newtype = Struct.new(:data1, :data2)
n = Newtype.new
C:
typedef struct {
int data1;
char data2;
} newtype;
newtype n;
OpenStruct sınıfı, C'deki anonim bir yapı bildirimi ile karşılaştırılabilir. Bu, programcının karmaşık türde bir örnek oluşturmasını sağlar .
Yakut:
o = OpenStruct.new(data1: 0, data2: 0)
o.data1 = 1
o.data2 = 2
C:
struct {
int data1;
char data2;
} o;
o.data1 = 1;
o.data2 = 2;
İşte bazı yaygın kullanım örnekleri.
OpenStructs, karmaları tüm karma anahtarlarına yanıt veren tek seferlik nesnelere kolayca dönüştürmek için kullanılabilir.
h = { a: 1, b: 2 }
o = OpenStruct.new(h)
o.a = 1
o.b = 2
Yapılar steno sınıf tanımları için yararlı olabilir.
class MyClass < Struct.new(:a,:b,:c)
end
m = MyClass.new
m.a = 1
OpenStructs, Yapılar'a göre önemli ölçüde daha fazla bellek kullanır ve daha yavaş performans gösterir.
require 'ostruct'
collection = (1..100000).collect do |index|
OpenStruct.new(:name => "User", :age => 21)
end
Sistemimde aşağıdaki kod 14 saniye içinde yürütüldü ve 1,5 GB bellek tüketti. Kilometreniz değişebilir:
User = Struct.new(:name, :age)
collection = (1..100000).collect do |index|
User.new("User",21)
end
Bu neredeyse anında bitti ve 26.6 MB bellek tüketti.
Struct
:
>> s = Struct.new(:a, :b).new(1, 2)
=> #<struct a=1, b=2>
>> s.a
=> 1
>> s.b
=> 2
>> s.c
NoMethodError: undefined method `c` for #<struct a=1, b=2>
OpenStruct
:
>> require 'ostruct'
=> true
>> os = OpenStruct.new(a: 1, b: 2)
=> #<OpenStruct a=1, b=2>
>> os.a
=> 1
>> os.b
=> 2
>> os.c
=> nil
Yeni yönteme ilişkin API'ya bir göz atın. Orada birçok fark bulunabilir.
Şahsen, OpenStruct'ı çok seviyorum, çünkü nesnenin yapısını önceden tanımlamak zorunda değilim ve sadece istediğim gibi şeyler eklemek zorunda değilim. Bu onun ana (dis) avantajı olacağını tahmin?
@Robert kodunu kullanarak, karşılaştırma öğesine Hashie :: Mash'i ekledim ve bu sonucu aldım:
user system total real
Hashie::Mash slow 3.600000 0.000000 3.600000 ( 3.755142)
Hashie::Mash fast 3.000000 0.000000 3.000000 ( 3.318067)
OpenStruct slow 11.200000 0.010000 11.210000 ( 12.095004)
OpenStruct fast 10.900000 0.000000 10.900000 ( 12.669553)
Struct slow 0.370000 0.000000 0.370000 ( 0.470550)
Struct fast 0.140000 0.000000 0.140000 ( 0.145161)
Aslında soruya bir cevap değil, performansı önemsiyorsanız çok önemli bir husustur . Her OpenStruct
işlem oluşturduğunuzda , yöntem önbelleğini temizlediğini, yani uygulamanızın daha yavaş çalışacağını unutmayın. Yavaşlık ya da değil, OpenStruct
sadece kendi başına nasıl çalıştığı ile ilgili değildir, aynı zamanda bunları kullanmanın tüm uygulamaya getirdiği sonuçlar : https://github.com/charliesome/charlie.bz/blob/master/posts/things-that -clear-rubys-method-cache.md # openstructs