Tôi đã làm việc với OO MATLAB được một thời gian và cuối cùng đã xem xét các vấn đề hiệu suất tương tự.
Câu trả lời ngắn gọn là: có, OOP của MATLAB là loại chậm. Có rất nhiều phương thức gọi phương thức, cao hơn các ngôn ngữ OO chính thống và bạn không thể làm gì nhiều với nó. Một phần lý do có thể là MATLAB thành ngữ sử dụng mã "được vector hóa" để giảm số lượng cuộc gọi phương thức và chi phí cho mỗi cuộc gọi không phải là ưu tiên cao.
Tôi đã đánh giá hiệu năng bằng cách viết các hàm "nop" không làm gì như các loại hàm và phương thức khác nhau. Dưới đây là một số kết quả điển hình.
>> tên gọi
Máy tính: PCWIN Phát hành: 2009b
Gọi mỗi chức năng / phương thức 100000 lần
Hàm nop (): 0,02261 giây 0,23 usec mỗi cuộc gọi
Hàm nop1-5 (): 0,02182 giây 0,22 usec mỗi cuộc gọi
chức năng con nop (): 0,02244 giây 0,22 usec mỗi cuộc gọi
@ () [] chức năng ẩn danh: 0,08461 giây 0,85 usec mỗi cuộc gọi
phương pháp nop (obj): 0,24664 giây 2,47 usec mỗi cuộc gọi
Các phương thức nop1-5 (obj): 0,23469 giây 2,35 usec mỗi cuộc gọi
Hàm riêng tư nop (): 0,02197 giây 0,22 usec mỗi cuộc gọi
classdef nop (obj): 0.90547 giây 9,05 usec mỗi cuộc gọi
classdef obj.nop (): 1.75522 giây 17.55 usec mỗi cuộc gọi
classdef private_nop (obj): 0.84738 giây 8.47 usec mỗi cuộc gọi
classdef nop (obj) (m-file): 0.90560 giây 9.06 usec mỗi cuộc gọi
classdef class.staticnop (): 1.16361 giây 11,64 usec mỗi cuộc gọi
Java nop (): 2.43035 giây 24.30 usec mỗi cuộc gọi
Java static_nop (): 0.87682 giây 8.77 usec mỗi cuộc gọi
Java nop () từ Java: 0,00014 giây 0,00 usec mỗi cuộc gọi
MEX mexnop (): 0.11409 giây 1.14 usec mỗi cuộc gọi
C nop (): 0,00001 giây 0,00 usec mỗi cuộc gọi
Kết quả tương tự trên R2008a đến R2009b. Đây là trên Windows XP x64 chạy MATLAB 32 bit.
"Java nop ()" là một phương thức Java không có gì được gọi từ bên trong một vòng mã M và bao gồm cả chi phí gửi MATLAB-to-Java với mỗi cuộc gọi. "Java nop () từ Java" là điều tương tự được gọi trong vòng lặp Java for () và không phải chịu hình phạt ranh giới đó. Lấy thời gian Java và C với một hạt muối; một trình biên dịch thông minh có thể tối ưu hóa hoàn toàn các cuộc gọi đi.
Cơ chế phạm vi gói là mới, được giới thiệu cùng lúc với các lớp classdef. Hành vi của nó có thể liên quan.
Một vài kết luận dự kiến:
- Các phương thức chậm hơn các hàm.
- Các phương thức kiểu mới (classdef) chậm hơn các phương thức kiểu cũ.
obj.nop()
Cú pháp mới chậm hơn nop(obj)
cú pháp, ngay cả đối với cùng một phương thức trên một đối tượng classdef. Tương tự cho các đối tượng Java (không hiển thị). Nếu bạn muốn đi nhanh, hãy gọi nop(obj)
.
- Chi phí cuộc gọi phương thức cao hơn (khoảng 2 lần) trong MATLAB 64 bit trên Windows. (Không được hiển thị.)
- Công văn phương thức MATLAB chậm hơn một số ngôn ngữ khác.
Nói tại sao điều này là như vậy sẽ chỉ là suy đoán về phía tôi. Nội bộ OO của công cụ MATLAB không công khai. Đây không phải là vấn đề được giải thích và được biên dịch theo từng se - MATLAB có JIT - nhưng cách gõ và cú pháp lỏng lẻo hơn của MATLAB có thể có nghĩa là làm việc nhiều hơn trong thời gian chạy. (Ví dụ: bạn không thể biết từ cú pháp một mình liệu "f (x)" là lệnh gọi hàm hay chỉ mục thành một mảng; nó phụ thuộc vào trạng thái của không gian làm việc trong thời gian chạy.) Có thể là do các định nghĩa lớp của MATLAB bị ràng buộc đến trạng thái hệ thống tập tin theo cách mà nhiều ngôn ngữ khác không có.
Vậy lam gi?
Một cách tiếp cận MATLAB thành ngữ cho vấn đề này là "vector hóa" mã của bạn bằng cách cấu trúc các định nghĩa lớp của bạn sao cho một cá thể đối tượng bao bọc một mảng; nghĩa là, mỗi trường của nó chứa các mảng song song (được gọi là tổ chức "phẳng" trong tài liệu MATLAB). Thay vì có một mảng các đối tượng, mỗi trường có các giá trị vô hướng, xác định các đối tượng là mảng và có các phương thức lấy mảng làm đầu vào và thực hiện các cuộc gọi được vector hóa trên các trường và đầu vào. Điều này làm giảm số lượng các cuộc gọi phương thức được thực hiện, hy vọng đủ rằng chi phí công văn không phải là một nút cổ chai.
Bắt chước một lớp C ++ hoặc Java trong MATLAB có lẽ sẽ không tối ưu. Các lớp Java / C ++ thường được xây dựng sao cho các đối tượng là các khối xây dựng nhỏ nhất, cụ thể nhất có thể (nghĩa là có rất nhiều lớp khác nhau) và bạn kết hợp chúng thành các mảng, các đối tượng tập hợp, v.v. và lặp lại chúng bằng các vòng lặp. Để tạo các lớp MATLAB nhanh, hãy chuyển phương pháp đó từ trong ra ngoài. Có các lớp lớn hơn có các trường là các mảng và gọi các phương thức vector hóa trên các mảng đó.
Vấn đề là sắp xếp mã của bạn để chơi theo các điểm mạnh của ngôn ngữ - xử lý mảng, toán học véc tơ - và tránh các điểm yếu.
EDIT: Kể từ bài đăng gốc, R2010b và R2011a đã xuất hiện. Bức tranh tổng thể là như nhau, với các cuộc gọi MCOS trở nên nhanh hơn một chút và các cuộc gọi phương thức kiểu cũ và Java ngày càng chậm hơn .
EDIT: Tôi đã từng có một số lưu ý ở đây về "độ nhạy đường dẫn" với bảng thời gian gọi chức năng bổ sung, trong đó thời gian chức năng bị ảnh hưởng bởi cách đường dẫn Matlab được định cấu hình, nhưng dường như đó là sự quang sai trong thiết lập mạng cụ thể của tôi tại thời gian. Biểu đồ trên phản ánh thời gian điển hình của tính ưu việt của các bài kiểm tra của tôi theo thời gian.
Cập nhật: R2011b
EDIT (2/13/2012): R2011b đã hết, và hình ảnh hiệu suất đã thay đổi đủ để cập nhật điều này.
Arch: PCWIN Phát hành: 2011b
Máy: R2011b, Windows XP, 8x Core i7-2600 @ 3.40GHz, RAM 3 GB, NVIDIA NVS 300
Thực hiện mỗi thao tác 100000 lần
tổng số phong cách trên mỗi cuộc gọi
Hàm nop (): 0,01578 0,16
nop (), hủy vòng lặp 10 lần: 0,01477 0,15
nop (), hủy vòng lặp 100x: 0,01518 0,15
chức năng con nop (): 0,01559 0,16
@ () [] Hàm ẩn danh: 0,06400 0,64
phương pháp nop (obj): 0,28482 2,85
nop () hàm riêng: 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
hằng số classdef: 1.51890 15.19
tài sản classdef: 0,12992 1,30
thuộc tính classdef với getter: 1.39912 13.99
+ Hàm pkg.nop (): 0.87345 8.73
+ pkg.nop () từ bên trong + pkg: 0.80501 8.05
Java obj.nop (): 1.86378 18.64
Java nop (obj): 0.22645 2.26
Java feval ('nop', obj): 0,52544 5,25
Java Klass.static_nop (): 0,35357 3,54
Java obj.nop () từ Java: 0,00010 0,00
MEXnop (): 0,08709 0,87
C nop (): 0,00001 0,00
j () (dựng sẵn): 0,00251 0,03
Tôi nghĩ rằng kết quả cuối cùng là:
- Phương pháp MCOS / classdef nhanh hơn. Chi phí bây giờ ngang bằng với các lớp kiểu cũ, miễn là bạn sử dụng
foo(obj)
cú pháp. Vì vậy, tốc độ phương thức không còn là lý do để gắn bó với các lớp kiểu cũ trong hầu hết các trường hợp. (Kudos, MathWorks!)
- Đặt các chức năng trong không gian tên làm cho chúng chậm. (Không mới trong R2011b, chỉ mới trong thử nghiệm của tôi.)
Cập nhật: R2014a
Tôi đã xây dựng lại mã điểm chuẩn và chạy nó trên R2014a.
Matlab R2014a trên PCWIN64
Matlab 8.3.0.532 (R2014a) / Java 1.7.0_11 trên PCWIN64 Windows 7 6.1 (eilonwy-win7)
Máy: CPU Core i7-3615QM @ 2.30GHz, RAM 4 GB (Nền tảng ảo VMware)
nIters = 100000
Thời gian hoạt động (Giansec)
hàm nop (): 0,14
hàm con nop (): 0,14
@ () [] Hàm ẩn danh: 0,69
phương pháp nop (obj): 3.28
nop () fcn riêng trên @ class: 0.14
classdef nop (obj): 5.30
classdef obj.nop (): 10,78
classdef pivate_nop (obj): 4,88
classdef class.static_nop (): 11.81
hằng số classdef: 4.18
tài sản hạng nhất: 1,18
tài sản classdef với getter: 19,26
+ Hàm pkg.nop (): 4.03
+ pkg.nop () từ bên trong + pkg: 4.16
feval ('nop'): 2,31
feval (@nop): 0,22
eval ('nop'): 59,46
Java obj.nop (): 26,07
Java nop (obj): 3,72
Java feval ('nop', obj): 9,25
Java Klass.staticNop (): 10,54
Java obj.nop () từ Java: 0,01
MEXnop (): 0,91
dựng sẵn j (): 0,02
cấu trúc truy cập trường s.foo: 0.14
isempty (liên tục): 0,00
Cập nhật: R2015b: Đối tượng đã nhanh hơn!
Đây là kết quả R2015b, được cung cấp bởi @Shaken. Đây là một thay đổi lớn : OOP nhanh hơn đáng kể và bây giờ obj.method()
cú pháp nhanh như method(obj)
và nhanh hơn nhiều so với các đối tượng OOP cũ.
Matlab R2015b trên PCWIN64
Matlab 8.6.0.267246 (R2015b) / Java 1.7.0_60 trên PCWIN64 Windows 8 6.2 (lắc nanit)
Máy: CPU Core i7-4720HQ @ 2.60GHz, RAM 16 GB (20378)
nIters = 100000
Thời gian hoạt động (Giansec)
Hàm nop (): 0,04
hàm con nop (): 0,08
@ () [] hàm ẩn danh: 1,83
phương pháp nop (obj): 3.15
nop () fcn riêng trên @ class: 0,04
classdef nop (obj): 0,28
classdef obj.nop (): 0,31
classdef pivate_nop (obj): 0,34
classdef class.static_nop (): 0,05
hằng số classdef: 0,25
tài sản classdef: 0,25
thuộc tính classdef với getter: 0,64
+ hàm pkg.nop (): 0,04
+ pkg.nop () từ bên trong + pkg: 0,04
feval ('nop'): 8.26
feval (@nop): 0,63
eval ('nop'): 21,22
Java obj.nop (): 14,15
Java nop (obj): 2.50
Java feval ('nop', obj): 10.30
Java Klass.staticNop (): 24,48
Java obj.nop () từ Java: 0,01
MEXnop (): 0,33
dựng sẵn j (): 0,15
cấu trúc truy cập trường s.foo: 0,25
isempty (liên tục): 0,13
Cập nhật: R2018a
Đây là kết quả R2018a. Đó không phải là bước nhảy lớn mà chúng ta đã thấy khi công cụ thực thi mới được giới thiệu vào R2015b, nhưng nó vẫn là một năm đáng kể so với cải tiến hàng năm. Đáng chú ý, xử lý chức năng ẩn danh có cách nhanh hơn.
Matlab R2018a trên MACI64
Matlab 9.4.0.813654 (R2018a) / Java 1.8.0_144 trên MACI64 Mac OS X 10.13.5 (eilonwy)
Máy: CPU Core i7-3615QM @ 2.30GHz, RAM 16 GB
nIters = 100000
Thời gian hoạt động (Giansec)
hàm nop (): 0,03
hàm con nop (): 0,04
@ () [] hàm ẩn danh: 0,16
classdef nop (obj): 0,16
classdef obj.nop (): 0,17
classdef pivate_nop (obj): 0.16
classdef class.static_nop (): 0,03
hằng số classdef: 0,16
tài sản classdef: 0,13
thuộc tính classdef với getter: 0,39
+ Hàm pkg.nop (): 0,02
+ pkg.nop () từ bên trong + pkg: 0,02
feval ('nop'): 15.62
feval (@nop): 0,43
eval ('nop'): 32,08
Java obj.nop (): 28,77
Java nop (obj): 8.02
Java feval ('nop', obj): 21,85
Java Klass.staticNop (): 45,49
Java obj.nop () từ Java: 0,03
MEXnop (): 3,54
dựng sẵn j (): 0.10
cấu trúc truy cập trường s.foo: 0.16
isempty (liên tục): 0,07
Cập nhật: R2018b và R2019a: Không thay đổi
Không có thay đổi đáng kể. Tôi không bận tâm để bao gồm các kết quả kiểm tra.
Mã nguồn cho điểm chuẩn
Tôi đã đặt mã nguồn cho các điểm chuẩn này trên GitHub, được phát hành theo Giấy phép MIT. https://github.com/apjanke/matlab-bench