Saya telah bekerja dengan OO MATLAB untuk sementara waktu, dan akhirnya melihat masalah kinerja yang serupa.
Jawaban singkatnya adalah: ya, OOP MATLAB agak lambat. Ada overhead panggilan metode yang substansial, lebih tinggi dari bahasa OO arus utama, dan tidak banyak yang dapat Anda lakukan. Sebagian alasannya mungkin karena MATLAB idiomatik menggunakan kode "vektor" untuk mengurangi jumlah panggilan metode, dan overhead per panggilan bukan prioritas tinggi.
Saya membandingkan kinerja dengan menulis fungsi "nop" do-nothing sebagai berbagai jenis fungsi dan metode. Berikut adalah beberapa hasil yang khas.
>> call_nops
Komputer: PCWIN Rilis: 2009b
Memanggil setiap fungsi / metode 100000 kali
fungsi nop (): 0,02261 detik 0,23 usec per panggilan
nop1-5 () fungsi: 0,02182 detik 0,22 usec per panggilan
subfungsi nop (): 0,02244 dt 0,22 usec per panggilan
@ () [] fungsi anonim: 0,08461 detik 0,85 usec per panggilan
nop (obj) method: 0,24664 dtk 2,47 usec per panggilan
metode nop1-5 (obj): 0,23469 dtk 2,35 usec per panggilan
nop () fungsi pribadi: 0,02197 detik 0,22 usec per panggilan
classdef nop (obj): 0.90547 dt 9.05 usec per panggilan
classdef obj.nop (): 1,75522 detik 17,55 usec per panggilan
classdef private_nop (obj): 0.84738 detik 8.47 usec per panggilan
classdef nop (obj) (m-file): 0,90560 dt 9,06 usec per panggilan
classdef class.staticnop (): 1,16361 detik 11,64 usec per panggilan
Java nop (): 2,43035 detik 24,30 usec per panggilan
Java static_nop (): 0,87682 dtk 8,77 usec per panggilan
Java nop () dari Java: 0,00014 detik 0,00 usec per panggilan
MEX mexnop (): 0,11409 dtk 1,14 usec per panggilan
C nop (): 0,00001 dtk 0,00 usec per panggilan
Hasil serupa pada R2008a hingga R2009b. Ini pada Windows XP x64 yang menjalankan MATLAB 32-bit.
"Java nop ()" adalah metode Java yang tidak melakukan apa pun yang dipanggil dari dalam loop kode-M, dan termasuk overhead pengiriman MATLAB-ke-Java dengan setiap panggilan. "Java nop () from Java" adalah hal yang sama yang disebut dalam Java for () loop dan tidak dikenakan penalti batas itu. Ambil pewaktuan Java dan C dengan sebutir garam; kompiler yang cerdik dapat mengoptimalkan panggilan secara total.
Mekanisme pelingkupan paket baru, diperkenalkan pada waktu yang hampir bersamaan dengan kelas classdef. Perilakunya mungkin terkait.
Beberapa kesimpulan sementara:
- Metode lebih lambat dari fungsi.
- Metode gaya baru (classdef) lebih lambat dari metode gaya lama.
obj.nop()
Sintaks baru lebih lambat dari nop(obj)
sintaks, bahkan untuk metode yang sama pada objek classdef. Sama untuk objek Java (tidak ditampilkan). Jika Anda ingin cepat, hubungi nop(obj)
.
- Metode panggilan overhead lebih tinggi (sekitar 2x) di MATLAB 64-bit pada Windows. (Tidak ditampilkan.)
- Pengiriman metode MATLAB lebih lambat dari beberapa bahasa lain.
Mengatakan mengapa ini hanya akan menjadi spekulasi di pihak saya. OO internal engine MATLAB tidak bersifat publik. Ini bukan masalah yang ditafsirkan vs dikompilasi per se - MATLAB memiliki JIT - tetapi mengetik dan sintaksis MATLAB yang lebih longgar mungkin berarti lebih banyak pekerjaan pada saat dijalankan. (Misalnya Anda tidak dapat mengetahui dari sintaks saja apakah "f (x)" adalah panggilan fungsi atau indeks ke dalam array; itu tergantung pada keadaan ruang kerja pada saat run time.) Ini mungkin karena definisi kelas MATLAB diikat ke status filesystem dengan cara yang banyak bahasa lain tidak.
Jadi, apa yang harus dilakukan?
Pendekatan MATLAB idiomatik untuk ini adalah "membuat vektor" kode Anda dengan menyusun definisi kelas Anda sedemikian rupa sehingga instance objek membungkus array; yaitu, masing-masing bidangnya memegang array paralel (disebut organisasi "planar" dalam dokumentasi MATLAB). Alih-alih memiliki array objek, masing-masing dengan bidang memegang nilai skalar, menentukan objek yang merupakan array sendiri, dan meminta metode mengambil array sebagai input, dan membuat panggilan vektor pada bidang dan input. Ini mengurangi jumlah panggilan metode yang dilakukan, semoga cukup bahwa biaya pengiriman bukan hambatan.
Meniru kelas C ++ atau Java di MATLAB mungkin tidak akan optimal. Kelas Java / C ++ biasanya dibangun sedemikian rupa sehingga objek adalah blok bangunan terkecil, sespesifik mungkin (yaitu, banyak kelas berbeda), dan Anda menyusunnya dalam array, koleksi objek, dll, dan beralih di atasnya dengan loop. Untuk membuat kelas MATLAB cepat, putar pendekatan luar ke dalam. Memiliki kelas yang lebih besar yang bidangnya adalah array, dan memanggil metode vektor pada array tersebut.
Intinya adalah untuk mengatur kode Anda untuk bermain dengan kekuatan bahasa - penanganan array, matematika vektor - dan menghindari titik lemah.
EDIT: Sejak posting asli, R2010b dan R2011a telah keluar. Gambaran keseluruhannya sama, dengan panggilan MCOS sedikit lebih cepat, dan Java dan panggilan metode lama semakin lambat .
EDIT: Saya dulu memiliki beberapa catatan di sini pada "sensitivitas jalur" dengan tabel tambahan waktu panggilan fungsi, di mana waktu fungsi dipengaruhi oleh bagaimana jalur Matlab dikonfigurasi, tapi itu tampaknya merupakan penyimpangan dari pengaturan jaringan khusus saya di waktu. Bagan di atas mencerminkan waktu yang tipikal dari dominannya tes saya dari waktu ke waktu.
Pembaruan: R2011b
EDIT (2/13/2012): R2011b keluar, dan gambar kinerja telah cukup berubah untuk memperbarui ini.
Arch: PCWIN Release: 2011b
Mesin: R2011b, Windows XP, 8x Core i7-2600 @ 3.40GHz, 3 GB RAM, NVIDIA NVS 300
Melakukan setiap operasi 100000 kali
gaya total µsec per panggilan
fungsi nop (): 0,01578 0,16
nop (), 10x loop membuka gulungan: 0,01477 0,15
nop (), 100x loop membuka gulungan: 0,01518 0,15
subfungsi nop (): 0,01559 0,16
@ () [] fungsi anonim: 0,06400 0,64
metode nop (obj): 0.28482 2.85
nop () fungsi pribadi: 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
konstanta classdef: 1.51890 15.19
properti classdef: 0.12992 1.30
properti classdef dengan pengambil: 1.39912 13.99
+ fungsi pkg.nop (): 0.87345 8.73
+ pkg.nop () dari dalam + 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 () dari Java: 0,00010 0,00
MEX mexnop (): 0,08709 0,87
C nop (): 0,00001 0,00
j () (builtin): 0,00251 0,03
Saya pikir hasilnya adalah:
- Metode MCOS / classdef lebih cepat. Biaya sekarang setara dengan kelas gaya lama, selama Anda menggunakan
foo(obj)
sintaks. Jadi kecepatan metode tidak lagi menjadi alasan untuk tetap menggunakan kelas gaya lama dalam banyak kasus. (Kudos, MathWorks!)
- Menempatkan fungsi dalam ruang nama membuatnya lambat. (Bukan baru di R2011b, hanya baru dalam pengujian saya.)
Pembaruan: R2014a
Saya telah merekonstruksi kode pembandingan dan menjalankannya pada R2014a.
Matlab R2014a pada PCWIN64
Matlab 8.3.0.532 (R2014a) / Java 1.7.0_11 pada PCWIN64 Windows 7 6.1 (eilonwy-win7)
Mesin: Core i7-3615QM CPU @ 2.30GHz, 4 GB RAM (Platform Virtual VMware)
nIters = 100000
Waktu Operasi (µsec)
fungsi nop (): 0,14
subfungsi nop (): 0,14
@ () [] fungsi anonim: 0.69
Metode nop (obj): 3.28
nop () fcn pribadi di @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
konstanta classdef: 4.18
properti classdef: 1.18
properti classdef dengan pengambil: 19.26
+ pkg.nop () fungsi: 4.03
+ pkg.nop () dari dalam + 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 () dari Java: 0,01
MEX mexnop (): 0,91
builtin j (): 0,02
akses lapangan struct s.foo: 0.14
isempty (persistent): 0.00
Pembaruan: R2015b: Objek jadi lebih cepat!
Inilah hasil R2015b, yang disediakan oleh @Shaked. Ini adalah perubahan besar : OOP secara signifikan lebih cepat, dan sekarang obj.method()
sintaksisnya secepat method(obj)
, dan jauh lebih cepat daripada objek OOP sebelumnya.
Matlab R2015b pada PCWIN64
Matlab 8.6.0.267246 (R2015b) / Java 1.7.0_60 pada PCWIN64 Windows 8 6.2 (nanit-shaked)
Mesin: Core i7-4720HQ CPU @ 2.60GHz, 16 GB RAM (20378)
nIters = 100000
Waktu Operasi (µsec)
fungsi nop (): 0,04
subfungsi nop (): 0,08
@ () [] fungsi anonim: 1,83
metode nop (obj): 3.15
nop () fcn pribadi di @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
konstanta classdef: 0.25
properti classdef: 0,25
properti classdef dengan pengambil: 0.64
+ pkg.nop () fungsi: 0,04
+ pkg.nop () dari dalam + 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 () dari Java: 0,01
MEX mexnop (): 0,33
builtin j (): 0,15
akses lapangan struct s.foo: 0.25
isempty (persistent): 0.13
Pembaruan: R2018a
Inilah hasil R2018a. Ini bukan lompatan besar yang kami lihat ketika mesin eksekusi baru diperkenalkan di R2015b, tapi ini masih merupakan peningkatan yang cukup berarti dari tahun ke tahun. Khususnya, fungsi anonim menangani lebih cepat.
Matlab R2018a pada MACI64
Matlab 9.4.0.813654 (R2018a) / Java 1.8.0_144 pada MACI64 Mac OS X 10.13.5 (eilonwy)
Mesin: Core i7-3615QM CPU @ 2.30GHz, 16 GB RAM
nIters = 100000
Waktu Operasi (µsec)
fungsi nop (): 0,03
subfungsi nop (): 0,04
@ () [] fungsi anonim: 0.16
classdef nop (obj): 0.16
classdef obj.nop (): 0,17
classdef pivate_nop (obj): 0.16
classdef class.static_nop (): 0,03
konstanta classdef: 0.16
properti classdef: 0,13
properti classdef dengan pengambil: 0.39
+ pkg.nop () fungsi: 0,02
+ pkg.nop () dari dalam + 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 () dari Java: 0,03
MEX mexnop (): 3,54
builtin j (): 0,10
akses lapangan struct s.foo: 0.16
isempty (persistent): 0,07
Pembaruan: R2018b dan R2019a: Tidak ada perubahan
Tidak ada perubahan signifikan. Saya tidak repot memasukkan hasil tes.
Kode Sumber untuk Tolok Ukur
Saya telah memasukkan kode sumber untuk benchmark ini di GitHub, dirilis di bawah Lisensi MIT. https://github.com/apjanke/matlab-bench