Struct를 사용해야 하는 경우와OpenStruct?
일반적으로 Struct와 비교하여 OpenStruct를 사용할 때의 장점과 단점은 무엇입니까?어떤 유형의 일반적인 사용 사례가 각각 적합합니까?
와 함께OpenStruct
임의로 속성을 만들 수 있습니다.aStruct
그러나 속성을 생성할 때 속성이 정의되어 있어야 합니다.다른 것보다 하나를 선택하는 것은 주로 나중에 속성을 추가할 수 있는지 여부에 따라 결정되어야 합니다.
그들을 생각하는 방법은 한 쪽은 해시이고 다른 쪽은 계급 사이의 스펙트럼의 중간점입니다.그들은 데이터 간의 관계가 데이터보다 더 구체적이라는 것을 의미합니다.Hash
수업처럼 인스턴스 메소드가 없어요예를 들어, 함수에 대한 여러 옵션은 해시에서 의미가 있습니다. 관련성이 거의 없습니다.기능에 필요한 이름, 이메일 및 전화 번호를 함께 패키지로 만들 수 있습니다.Struct
또는OpenStruct
이름, 전자 메일 및 전화 번호가 "첫 번째 성" 및 "마지막, 첫 번째" 형식으로 이름을 제공하는 방법이 필요한 경우 클래스를 만들어야 합니다.
기타 벤치마크:
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
스스로 실행하지 않고 벤치마크 결과에 대한 아이디어를 얻고 싶어하는 참을성 없는 사람들을 위해 위의 코드의 출력이 있습니다(MB Pro 2.4).GHz 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)
업데이트:
백만 개의 인스턴스를 생성하기 위한 시간:
0.357788 seconds elapsed for Class.new (Ruby 2.5.5)
0.764953 seconds elapsed for Struct (Ruby 2.5.5)
0.842782 seconds elapsed for Hash (Ruby 2.5.5)
2.211959 seconds elapsed for OpenStruct (Ruby 2.5.5)
0.213175 seconds elapsed for Class.new (Ruby 2.6.3)
0.335341 seconds elapsed for Struct (Ruby 2.6.3)
0.836996 seconds elapsed for Hash (Ruby 2.6.3)
2.070901 seconds elapsed for OpenStruct (Ruby 2.6.3)
0.936016 seconds elapsed for Class.new (Ruby 2.7.2)
0.453067 seconds elapsed for Struct (Ruby 2.7.2)
1.016676 seconds elapsed for Hash (Ruby 2.7.2)
1.482318 seconds elapsed for OpenStruct (Ruby 2.7.2)
0.421272 seconds elapsed for Class.new (Ruby 3.0.0)
0.322617 seconds elapsed for Struct (Ruby 3.0.0)
0.719928 seconds elapsed for Hash (Ruby 3.0.0)
35.130777 seconds elapsed for OpenStruct (Ruby 3.0.0) (oops!)
0.443975 seconds elapsed for Class.new (Ruby 3.0.1)
0.348031 seconds elapsed for Struct (Ruby 3.0.1)
0.737662 seconds elapsed for Hash (Ruby 3.0.1)
16.264204 seconds elapsed for SmartHash (Ruby 3.0.1) (meh)
53.396924 seconds elapsed for OpenStruct (Ruby 3.0.1) (oops!)
참조: 루비 3.0.0 버그 #18032는 버그가 아닌 기능이기 때문에 닫혔습니다.
인용문:
OpenStruct는 이제 "반패턴"으로 간주되므로 더 이상 OpenStruct를 사용하지 않는 것이 좋습니다.
[Ruby team] 성능보다 정확성을 우선시하여 Ruby 2.2와 유사한 솔루션으로 돌아왔습니다.
이전 답변:
Ruby 2.4.1 기준으로 OpenStruct와 Struct는 속도 면에서 훨씬 더 가깝습니다.https://stackoverflow.com/a/43987844/128421 을 참조하십시오.
완성도를 위해:구조 대.수업 대.해시 대.오픈 스트럭처
Ruby 1.9.2에서 burtlo와 유사한 코드 실행(4개 코어 중 1개 x86_64, 8GB RAM) [열을 정렬하도록 편집된 테이블]:
1 Mio Structs 생성: 1.43초, 219MB/90MB(virt/res)1개의 Mio 클래스 인스턴스 생성: 1.43초, 219MB/90MB(virt/res)1 Mio 해시 생성: 4.46초, 493MB / 364MB(virt/res)1 Mio OpenStructs 생성: 415.13초, 2464MB / 2.3GB(virt/res) # 해시보다 최대 100배 느림100K OpenStructs 생성: 10.96초, 369MB / 242MB(virt/res)
OpenStructs는 너무 느리고 메모리 집약적이며 대규모 데이터 세트에 적합하게 확장되지 않습니다.
결과를 재현하기 위한 스크립트는 다음과 같습니다.
require 'ostruct'
require 'smart_hash'
MAX = 1_000_000
class C;
attr_accessor :name, :age;
def initialize(name, age)
self.name = name
self.age = age
end
end
start = Time.now
collection = (1..MAX).collect do |i|
C.new('User', 21)
end; 1
stop = Time.now
puts " #{stop - start} seconds elapsed for Class.new (Ruby #{RUBY_VERSION})"
s = Struct.new(:name, :age)
start = Time.now
collection = (1..MAX).collect do |i|
s.new('User', 21)
end; 1
stop = Time.now
puts " #{stop - start} seconds elapsed for Struct (Ruby #{RUBY_VERSION})"
start = Time.now
collection = (1..MAX).collect do |i|
{:name => "User" , :age => 21}
end; 1
stop = Time.now
puts " #{stop - start} seconds elapsed for Hash (Ruby #{RUBY_VERSION})"
start = Time.now
collection = (1..MAX).collect do |i|
s = SmartHash[].merge( {:name => "User" , :age => 21} )
end; 1
stop = Time.now
puts " #{stop - start} seconds elapsed for SmartHash (Ruby #{RUBY_VERSION})"
start = Time.now
collection = (1..MAX).collect do |i|
OpenStruct.new(:name => "User" , :age => 21)
end; 1
stop = Time.now
puts " #{stop - start} seconds elapsed for OpenStruct (Ruby #{RUBY_VERSION})"
두 가지의 사용 사례는 상당히 다릅니다.
1는 Ruby 1.9 Struct와 .struct
다의 선언인 루비Struct.new
필드 이름 집합을 인수로 사용하고 새 클래스를 반환합니다.에서 a 찬가지로에, C서마, astruct
선언은 필드 집합을 사용하고 프로그래머가 내장된 유형과 마찬가지로 새로운 복합 유형을 사용할 수 있도록 합니다.
루비:
Newtype = Struct.new(:data1, :data2)
n = Newtype.new
C:
typedef struct {
int data1;
char data2;
} newtype;
newtype n;
OpenStruct 클래스는 C의 익명 구조 선언과 비교할 수 있습니다.프로그래머가 복잡한 유형의 인스턴스를 만들 수 있습니다.
루비:
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;
다음은 몇 가지 일반적인 사용 사례입니다.
OpenStructs를 사용하여 해시를 모든 해시 키에 응답하는 일회성 개체로 쉽게 변환할 수 있습니다.
h = { a: 1, b: 2 }
o = OpenStruct.new(h)
o.a = 1
o.b = 2
구조체는 단축형 클래스 정의에 유용할 수 있습니다.
class MyClass < Struct.new(:a,:b,:c)
end
m = MyClass.new
m.a = 1
OpenStructs는 훨씬 더 많은 메모리를 사용하고 Structs에 비해 성능이 느립니다.
require 'ostruct'
collection = (1..100000).collect do |index|
OpenStruct.new(:name => "User", :age => 21)
end
내 시스템에서 다음 코드는 14초 만에 실행되었고 1.5GB의 메모리를 소비했습니다.마일리지는 다음과 같이 다를 수 있습니다.
User = Struct.new(:name, :age)
collection = (1..100000).collect do |index|
User.new("User",21)
end
거의 즉각적으로 완료되었으며 26.6MB의 메모리를 사용했습니다.
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
새로운 방법과 관련하여 API를 살펴보십시오.그곳에서 많은 차이점을 발견할 수 있습니다.
개인적으로, 저는 OpenStruct를 꽤 좋아합니다. 왜냐하면 저는 객체의 구조를 미리 정의할 필요가 없고 제가 원하는 대로 추가할 수 있기 때문입니다.그것이 그것의 주요 장점이 될 것 같습니다.
- http://www.ruby-doc.org/core/classes/Struct.html
- http://www.ruby-doc.org/stdlib/libdoc/ostruct/rdoc/classes/OpenStruct.html
@Robert 코드를 사용하여 해시를 추가합니다.: 벤치마크 항목에 매쉬하여 다음과 같은 결과를 얻었습니다.
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)
실제로 질문에 대한 대답이 아니라 성능에 관심이 있다면 매우 중요한 고려 사항입니다.다음을 생성할 때마다OpenStruct
이 작업은 메서드 캐시를 지웁니다. 즉, 응용 프로그램의 성능이 저하됩니다. OpenStruct
https://github.com/charliesome/charlie.bz/blob/master/posts/things-that-clear-rubys-method-cache.md#openstructs 은 단순히 어떻게 작동하는지에 대한 것이 아니라, 이를 사용하는 것이 전체 애플리케이션에 미치는 영향에 대한 것입니다.
언급URL : https://stackoverflow.com/questions/1177594/when-should-i-use-struct-vs-openstruct
'programing' 카테고리의 다른 글
XML on Fragments를 사용하여 버튼 클릭을 처리하는 방법 Click in Fragments (0) | 2023.06.04 |
---|---|
Git에서의 병합이 SVN에서의 병합보다 어떻게 그리고/또는 왜 더 낫습니까? (0) | 2023.06.04 |
delete_all vs destroy_all? (0) | 2023.06.04 |
HTML을 사용하여 문서의 모든 인쇄 페이지에서 머리글과 바닥글을 인쇄하는 방법은 무엇입니까? (0) | 2023.06.04 |
안드로이드 애플리케이션에서 이메일을 보내는 방법은 무엇입니까? (0) | 2023.06.04 |