Aku bereksperimen dengan MATLAB OOP , sebagai mulai saya menirukan saya C ++ 's kelas Logger dan aku menempatkan semua saya fungsi pembantu string dalam kelas String, berpikir itu akan menjadi besar untuk dapat melakukan hal-hal seperti a + b
, a == b
, a.find( b )
bukannya strcat( a b )
, strcmp( a, b )
, ambil elemen pertama strfind( a, b )
, dll.
Masalahnya: perlambatan
Saya menggunakan hal-hal di atas untuk digunakan dan segera melihat penurunan drastis . Apakah saya melakukan kesalahan (yang tentu saja mungkin karena saya memiliki pengalaman MATLAB yang agak terbatas), atau apakah OOP MATLAB hanya memperkenalkan banyak overhead?
Kasing uji saya
Inilah tes sederhana yang saya lakukan untuk string, pada dasarnya hanya menambahkan string dan menghapus bagian yang ditambahkan lagi:
Catatan: Jangan benar-benar menulis kelas String seperti ini dalam kode nyata! Matlab memiliki
string
tipe array asli sekarang, dan Anda harus menggunakannya.
classdef String < handle
....
properties
stringobj = '';
end
function o = plus( o, b )
o.stringobj = [ o.stringobj b ];
end
function n = Length( o )
n = length( o.stringobj );
end
function o = SetLength( o, n )
o.stringobj = o.stringobj( 1 : n );
end
end
function atest( a, b ) %plain functions
n = length( a );
a = [ a b ];
a = a( 1 : n );
function btest( a, b ) %OOP
n = a.Length();
a = a + b;
a.SetLength( n );
function RunProfilerLoop( nLoop, fun, varargin )
profile on;
for i = 1 : nLoop
fun( varargin{ : } );
end
profile off;
profile report;
a = 'test';
aString = String( 'test' );
RunProfilerLoop( 1000, @(x,y)atest(x,y), a, 'appendme' );
RunProfilerLoop( 1000, @(x,y)btest(x,y), aString, 'appendme' );
Hasil
Total waktu dalam detik, untuk 1000 iterasi:
btest 0,550 (dengan String.SetLength 0,138, String.plus 0,065, String.Length 0,057)
atest 0,015
Hasil untuk sistem logger juga: 0,1 detik untuk 1000 panggilan ke frpintf( 1, 'test\n' )
, 7 (!) Detik untuk 1000 panggilan ke sistem saya ketika menggunakan kelas String secara internal (OK, ia memiliki lebih banyak logika di dalamnya, tetapi dibandingkan dengan C ++: overhead sistem saya yang menggunakan std::string( "blah" )
dan std::cout
pada sisi output vs polos std::cout << "blah"
berada di urutan 1 milidetik.)
Apakah itu hanya overhead saat mencari fungsi kelas / paket?
Karena MATLAB diinterpretasikan, ia harus mencari definisi fungsi / objek pada saat run time. Jadi saya bertanya-tanya bahwa mungkin lebih banyak overhead yang terlibat dalam mencari kelas atau fungsi paket vs fungsi yang ada di jalur. Saya mencoba untuk menguji ini, dan itu hanya menjadi asing. Untuk mengesampingkan pengaruh kelas / objek, saya membandingkan memanggil fungsi di path vs fungsi dalam sebuah paket:
function n = atest( x, y )
n = ctest( x, y ); % ctest is in matlab path
function n = btest( x, y )
n = util.ctest( x, y ); % ctest is in +util directory, parent directory is in path
Hasil, dikumpulkan dengan cara yang sama seperti di atas:
atest 0,004 dtk, 0,001 dtk dalam ctest
btest 0,060 dtk, 0,014 dtk di util.ctest
Jadi, apakah semua overhead ini hanya berasal dari MATLAB yang menghabiskan waktu mencari definisi untuk implementasi OOPnya, sedangkan overhead ini tidak ada untuk fungsi-fungsi yang secara langsung berada di jalurnya?
for i = 1:this.get_n_quantities() if(strcmp(id,this.get_quantity_rlz(i).get_id())) ix = i; end end
memakan waktu 2,2 detik, sementaranq = this.get_n_quantities(); a = this.get_quantity_realizations(); for i = 1:nq c = a{i}; if(strcmp(id,c.get_id())) ix = i; end end
memakan waktu 0,01, dua pesanan magJawaban:
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.
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:
obj.nop()
Sintaks baru lebih lambat darinop(obj)
sintaks, bahkan untuk metode yang sama pada objek classdef. Sama untuk objek Java (tidak ditampilkan). Jika Anda ingin cepat, hubunginop(obj)
.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.
Saya pikir hasilnya adalah:
foo(obj)
sintaks. Jadi kecepatan metode tidak lagi menjadi alasan untuk tetap menggunakan kelas gaya lama dalam banyak kasus. (Kudos, MathWorks!)Pembaruan: R2014a
Saya telah merekonstruksi kode pembandingan dan menjalankannya pada R2014a.
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 secepatmethod(obj)
, dan jauh lebih cepat daripada objek OOP sebelumnya.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.
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
sumber
Kelas pegangan memiliki overhead tambahan dari pelacakan semua referensi ke dirinya sendiri untuk tujuan pembersihan.
Coba percobaan yang sama tanpa menggunakan kelas pegangan dan lihat apa hasil Anda.
sumber
Kinerja OO sangat tergantung pada versi MATLAB yang digunakan. Saya tidak dapat mengomentari semua versi, tetapi tahu dari pengalaman bahwa 2012a jauh lebih baik dari versi 2010. Tidak ada tolok ukur dan tidak ada angka untuk ditampilkan. Kode saya, secara eksklusif ditulis menggunakan kelas pegangan dan ditulis di bawah 2012a tidak akan berjalan sama sekali di bawah versi sebelumnya.
sumber
Sebenarnya tidak ada masalah dengan kode Anda, tetapi itu adalah masalah dengan Matlab. Saya pikir di dalamnya adalah semacam bermain-main agar terlihat seperti. Tidak lebih dari overhead untuk mengkompilasi kode kelas. Saya telah melakukan tes dengan titik kelas sederhana (sekali sebagai pegangan) dan yang lainnya (sekali sebagai kelas nilai)
ini tesnya
Hasil t1 =
12,0212% Menangani
t2 =
Nilai 12,0042%
t3 =
t4 =
Oleh karena itu untuk kinerja yang efisien, hindari penggunaan OOP sebagai gantinya struktur adalah pilihan yang baik untuk mengelompokkan variabel
sumber