나는 OO MATLAB과 한동안 일하고 있었고 비슷한 성능 문제를 보았습니다.
짧은 대답은 그렇습니다. MATLAB의 OOP는 느립니다. 주류 OO 언어보다 높은 메소드 호출 오버 헤드가 있으며 이에 대해 할 수있는 일은 많지 않습니다. 그 이유 중 하나는 관용적 MATLAB이 "벡터화 된"코드를 사용하여 메소드 호출 수를 줄이고 호출 당 오버 헤드가 우선 순위가 높지 않기 때문일 수 있습니다.
나는 아무 것도없는 "nop"함수를 다양한 유형의 함수와 메소드로 작성하여 성능을 벤치마킹했습니다. 다음은 일반적인 결과입니다.
>> call_nops
컴퓨터 : PCWIN 출시 : 2009b
각 함수 / 메소드를 100,000 번 호출
nop () 함수 : 호출 당 0.02261 초 0.23 usec
nop1-5 () 함수 : 호출 당 0.02182 초 0.22 usec
nop () 하위 함수 : 호출 당 0.02244 초 0.22 usec
@ () [] 익명 함수 : 호출 당 0.08461 초 0.85 usec
nop (obj) 방법 : 0.24664 초 2.47 회 호출 당
nop1-5 (obj) 메서드 : 호출 당 0.23469 초 2.35 usec
nop () 개인 함수 : 호출 당 0.02197 초 0.22 usec
classdef nop (obj) : 통화 당 0.90547 초 9.05 usec
classdef obj.nop () : 1.75522 초 17.55 호출 당 usec
classdef private_nop (obj) : 호출 당 0.84738 초 8.47 usec
classdef nop (obj) (m-file) : 0.90560 초 9.06 통화 당 usec
classdef class.staticnop () : 1.16361 초 11.64 통화 당
Java nop () : 통화 당 2.43035 초 24.30 usec
Java static_nop () : 호출 당 0.87682 초 8.77 usec
Java의 Java nop () : 호출 당 0.00014 초 0.00 usec
MEX mexnop () : 호출 당 0.11409 초 1.14 usec
C nop () : 통화 당 0.00001 초 0.00 usec
R2008a에서 R2009b까지 비슷한 결과. 32 비트 MATLAB을 실행하는 Windows XP x64에 있습니다.
"Java nop ()"는 M 코드 루프 내에서 호출되는 Java가 아닌 메소드이며 각 호출마다 MATLAB-to-Java 디스패치 오버 헤드를 포함합니다. "Java에서 Java nop ()"는 Java for () 루프에서 호출되는 것과 동일하며 해당 경계 불이익을 일으키지 않습니다. 소금 한 알로 Java 및 C 타이밍을 가져 가십시오. 영리한 컴파일러는 호출을 완전히 최적화 할 수 있습니다.
패키지 범위 지정 메커니즘은 새롭고 classdef 클래스와 거의 동시에 도입되었습니다. 동작이 관련 될 수 있습니다.
몇 가지 임시 결론 :
- 방법은 함수보다 느립니다.
- 새로운 스타일 (classdef) 메소드는 이전 스타일 메소드보다 느립니다.
- 새로운
obj.nop()
구문은 nop(obj)
classdef 객체의 동일한 메소드에서도 구문 보다 느립니다 . Java 객체 (표시되지 않음)와 동일합니다. 당신이 빨리 가고 싶은 경우, 전화 nop(obj)
.
- Windows의 64 비트 MATLAB에서 메서드 호출 오버 헤드가 더 높습니다 (약 2 배). (표시되지 않음)
- MATLAB 메소드 디스패치가 다른 언어보다 느립니다.
이것이 왜 그렇게 말하는지는 내 부분에 대한 추측 일뿐입니다. MATLAB 엔진의 OO 내부는 공개되지 않습니다. MATLAB에는 JIT가 있지만 해석 및 컴파일 된 문제 자체는 아니지만 MATLAB의 느슨한 타이핑 및 구문은 런타임에 더 많은 작업을 의미 할 수 있습니다. (예를 들어 "f (x)"가 함수 호출인지 또는 배열에 대한 인덱스인지 구문만으로는 알 수 없습니다. 런타임시 작업 공간의 상태에 따라 다릅니다.) MATLAB의 클래스 정의가 연결되어 있기 때문일 수 있습니다 다른 많은 언어들은 그렇지 않은 방식으로 파일 시스템 상태로
그래서 뭘 할건데?
이에 대한 관용적 인 MATLAB 접근 방식은 객체 인스턴스가 배열을 래핑하도록 클래스 정의를 구성하여 코드를 "벡터화"하는 것입니다. 즉, 각 필드는 병렬 배열을 보유합니다 (MATLAB 설명서에서 "평면"구성이라고 함). 각각 스칼라 값을 보유하는 필드가있는 객체의 배열을 갖는 대신, 스스로 배열 인 객체를 정의하고, 메소드가 배열을 입력으로 취하고 필드와 입력에 대해 벡터화 된 호출을 수행하게합니다. 이렇게하면 디스패치 오버 헤드가 병목 현상이되지 않도록 메소드 호출 수가 줄어 듭니다.
MATLAB에서 C ++ 또는 Java 클래스를 흉내내는 것은 아마도 최적이 아닐 것입니다. Java / C ++ 클래스는 일반적으로 객체가 가능한 한 가장 작은 빌딩 블록 (즉, 다양한 클래스)으로 작성되고 배열, 컬렉션 객체 등으로 작성하고 루프를 통해 반복합니다. 빠른 MATLAB 클래스를 만들려면 해당 접근 방식을 안쪽으로 돌리십시오. 필드가 배열 인 더 큰 클래스가 있고 해당 배열에서 벡터화 된 메소드를 호출하십시오.
요점은 배열 핸들링, 벡터화 된 수학과 같은 언어의 장점에 따라 코드를 정렬하고 약점을 피하는 것입니다.
편집 : 원래 게시물 이후 R2010b 및 R2011a가 나왔습니다. MCOS 호출이 약간 빨라지고 Java 및 이전 스타일 메소드 호출이 느려져 전체적인 그림은 동일 합니다.
편집 : 여기에 함수 호출 타이밍의 추가 테이블과 함께 "경로 감도"에 대한 메모가 있었는데, 여기서 함수 시간은 Matlab 경로 구성 방법에 의해 영향을 받았지만, 특정 네트워크 설정의 수차 인 것처럼 보입니다. 시간. 위의 차트는 시간이 지남에 따라 테스트의 우세한 시간을 반영합니다.
업데이트 : R2011b
편집 (2012 년 2 월 13 일) : R2011b가 종료되었으며 성능 사진이이를 업데이트하기에 충분하도록 변경되었습니다.
아치 : PCWIN 출시 : 2011b
머신 : R2011b, Windows XP, 8x Core i7-2600 @ 3.40GHz, 3GB RAM, NVIDIA NVS 300
각 작업을 100,000 번 수행
통화 당 총 스타일 µsec
nop () 함수 : 0.01578 0.16
nop (), 10 배 루프 언롤 : 0.01477 0.15
nop (), 100x 루프 언롤 : 0.01518 0.15
nop () 하위 함수 : 0.01559 0.16
@ () [] 익명 함수 : 0.06400 0.64
nop (obj) 방법 : 0.28482 2.85
nop () 전용 함수 : 0.01505 0.15
classdef nop (obj) : 0.43323 4.33
classdef obj.nop () : 0.81087 8.11
classdef private_nop (obj) : 0.32272 3.23
classdef class.staticnop () : 0.88959 8.90
classdef 상수 : 1.51890 15.19
classdef 속성 : 0.12992 1.30
게터가있는 classdef 속성 : 1.39912 13.99
+ pkg.nop () 함수 : 0.87345 8.73
+ pkg 내부에서 + pkg.nop () : 0.80501 8.05
자바 obj.nop () : 1.86378 18.64
자바 nop (obj) : 0.22645 2.26
자바 feval ( 'nop', obj) : 0.52544 5.25
자바 Klass.static_nop () : 0.35357 3.54
Java의 Java obj.nop () : 0.00010 0.00
MEX mexnop () : 0.08709 0.87
C nop () : 0.00001 0.00
j () (내장) : 0.00251 0.03
나는 이것의 결론은 다음과 같다고 생각한다.
- MCOS / classdef 메소드가 더 빠릅니다.
foo(obj)
구문 을 사용하는 한 비용은 이제 이전 스타일 클래스와 비슷 합니다. 따라서 메소드 속도는 더 이상 대부분의 경우 이전 스타일 클래스를 고수하는 이유가 아닙니다. (Kudos, MathWorks!)
- 네임 스페이스에 함수를 넣으면 속도가 느려집니다. (R2011b에서는 새로운 것이 아니라 내 테스트에서는 새로운 것입니다.)
업데이트 : R2014a
벤치마킹 코드를 재구성하고 R2014a에서 실행했습니다.
PCWIN64의 Matlab R2014a
PCWIN64 Windows 7 6.1의 Matlab 8.3.0.532 (R2014a) / Java 1.7.0_11 (eilonwy-win7)
머신 : Core i7-3615QM CPU @ 2.30GHz, 4GB RAM (VMware 가상 플랫폼)
니터 = 100000
작동 시간 (µsec)
nop () 함수 : 0.14
nop () 하위 함수 : 0.14
@ () [] 익명 함수 : 0.69
nop (obj) 방법 : 3.28
@class의 nop () private fcn : 0.14
classdef nop (obj) : 5.30
classdef obj.nop () : 10.78
classdef pivate_nop (obj) : 4.88
classdef class.static_nop () : 11.81
classdef 상수 : 4.18
classdef 속성 : 1.18
게터가있는 classdef 속성 : 19.26
+ pkg.nop () 함수 : 4.03
+ pkg 내부에서 + pkg.nop () : 4.16
feval ( 'nop') : 2.31
feval (@nop) : 0.22
eval ( 'nop') : 59.46
자바 obj.nop () : 26.07
자바 nop (obj) : 3.72
자바 feval ( 'nop', obj) : 9.25
자바 Klass.staticNop () : 10.54
Java의 Java obj.nop () : 0.01
MEX mexnop () : 0.91
내장 j () : 0.02
s.foo 필드 접근 : 0.14
비어 있음 (지속적) : 0.00
업데이트 : R2015b : 객체가 더 빨라졌습니다!
@Shaked가 친절하게 제공 한 R2015b 결과는 다음과 같습니다. 이것은 큰 변화입니다. OOP가 훨씬 빠르며 obj.method()
구문은 method(obj)
기존 OOP 객체보다 빠르며 훨씬 빠릅니다.
PCWIN64의 Matlab R2015b
PCWIN64 Windows 8 6.2의 Matlab 8.6.0.267246 (R2015b) / Java 1.7.0_60 (손떨림)
머신 : Core i7-4720HQ CPU @ 2.60GHz, 16GB RAM (20378)
니터 = 100000
작동 시간 (µsec)
nop () 함수 : 0.04
nop () 하위 함수 : 0.08
@ () [] 익명 함수 : 1.83
nop (obj) 방법 : 3.15
@class의 nop () private fcn : 0.04
classdef nop (obj) : 0.28
classdef obj.nop () : 0.31
classdef pivate_nop (obj) : 0.34
classdef class.static_nop () : 0.05
classdef 상수 : 0.25
classdef 속성 : 0.25
게터가있는 classdef 속성 : 0.64
+ pkg.nop () 함수 : 0.04
+ pkg 내부에서 + pkg.nop () : 0.04
feval ( 'nop') : 8.26
feval (@nop) : 0.63
평가 ( 'nop') : 21.22
자바 obj.nop () : 14.15
자바 nop (obj) : 2.50
자바 feval ( 'nop', obj) : 10.30
자바 Klass.staticNop () : 24.48
Java의 Java obj.nop () : 0.01
MEX mexnop () : 0.33
내장 j () : 0.15
s.foo 필드 접근 : 0.25
비어 있음 (영구적) : 0.13
업데이트 : R2018a
다음은 R2018a 결과입니다. 새로운 실행 엔진이 R2015b에 도입되었을 때 보았던 큰 도약은 아니지만 여전히 매년 개선되고 있습니다. 특히 익명 함수 핸들이 더 빨라졌습니다.
MACI64의 Matlab R2018a
MACI64 Mac OS X 10.13.5의 Matlab 9.4.0.813654 (R2018a) / Java 1.8.0_144 (eilonwy)
머신 : Core i7-3615QM CPU @ 2.30GHz, 16GB RAM
니터 = 100000
작동 시간 (µsec)
nop () 함수 : 0.03
nop () 하위 함수 : 0.04
@ () [] 익명 함수 : 0.16
classdef nop (obj) : 0.16
classdef obj.nop () : 0.17
classdef pivate_nop (obj) : 0.16
classdef class.static_nop () : 0.03
classdef 상수 : 0.16
classdef 속성 : 0.13
게터가있는 classdef 속성 : 0.39
+ pkg.nop () 함수 : 0.02
+ pkg 내부에서 + pkg.nop () : 0.02
feval ( 'nop') : 15.62
feval (@nop) : 0.43
eval ( 'nop') : 32.08
자바 obj.nop () : 28.77
자바 nop (obj) : 8.02
자바 feval ( 'nop', obj) : 21.85
자바 Klass.staticNop () : 45.49
Java의 Java obj.nop () : 0.03
MEX mexnop () : 3.54
내장 j () : 0.10
s.foo 필드 접근 : 0.16
비어 있음 (영구적) : 0.07
업데이트 : R2018b 및 R2019a : 변경 사항 없음
큰 변화가 없습니다. 나는 테스트 결과를 포함시키는 것을 귀찮게하지 않습니다.
벤치 마크 소스 코드
이 벤치 마크에 대한 소스 코드를 MIT 라이센스에 따라 릴리스 된 GitHub에 올렸습니다. https://github.com/apjanke/matlab-bench