149 votes

Est MATLAB OOP lent ou je fais quelque chose de mal ?

Je suis en train d'expérimenter avec MATLAB programmation orientée objet, pour un début, j'ai imité mon C++de l'Enregistreur de classes et je vais mettre toutes mes chaîne de fonctions d'assistance dans une classe String, pensant que ce serait génial de pouvoir faire des choses comme a + b, a == b, a.find( b ) au lieu d' strcat( a b ), strcmp( a, b ), récupérer le premier élément de strfind( a, b ), etc.

Le problème: ralentissement

J'ai mis au-dessus des choses à utiliser et immédiatement remarqué un drastique de ralentissement. Suis-je le fais mal (ce qui est certainement possible que j'ai plutôt limitée MATLAB de l'expérience), ou ne MATLAB POO juste introduire un tas de frais généraux?

Mon cas de test

Voici la simple test que j'ai fait pour la chaîne, fondamentalement, il suffit de concaténer une chaîne de caractères et la suppression de la partie annexée de nouveau:

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' );

Les résultats

Temps Total en secondes, pour 1000 itérations:

btest 0.550 (avec de la Ficelle.SetLength 0.138, Chaîne.plus de 0,065, Chaîne.Longueur 0.057)

atest 0.015

Les résultats pour le système d'enregistrement sont de la même façon: 0.1 secondes pour 1000 appels d' frpintf( 1, 'test\n' ), 7 (!) secondes pour 1000 appels à mon système lors de l'utilisation de la classe String en interne (OK, il est beaucoup plus logique, mais à comparer avec C++: la surcharge de mon système qui utilise std::string( "blah" ) et std::cout à la sortie vs plain std::cout << "blah" est de l'ordre de 1 milliseconde.)

Est-il juste de surcharge lors de la recherche de classe/fonctions de package?

Depuis MATLAB est interprété, c'est de chercher la définition d'une fonction ou de l'objet au moment de l'exécution. Donc, je me demandais que peut-être beaucoup plus de surcharge est impliqué dans la recherche de classe ou une fonction du package vs fonctions qui sont dans le chemin. J'ai essayé de le tester, et il est juste parfait inconnu. Pour écarter l'influence des classes/objets, j'ai comparé l'appel d'une fonction dans le chemin vs une fonction dans un paquet de:

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

Les résultats, rassemblés même manière que ci-dessus:

atest 0.004 sec, 0.001 sec, ctest

btest 0.060 sec, en 0.014 s en util.ctest

Donc, est-ce que ce surcharge juste à venir à partir de MATLAB passer du temps à la recherche des définitions pour la mise en œuvre de la programmation orientée objet, alors que cette charge n'est pas là pour les fonctions qui sont directement dans le chemin d'accès?

233voto

Andrew Janke Points 11942

J'ai travaillé avec OO MATLAB pour un moment, et finit par regarder similaires problèmes de performances.

La réponse courte est: oui, MATLAB programmation orientée objet est une sorte de lente. Il est important appel de la méthode des frais généraux, plus élevé que l'ensemble des langages à objets, et il n'y a pas beaucoup que vous pouvez faire à ce sujet. Partie de la raison peut être que idiomatiques MATLAB utilise "vectorisé" code afin de réduire le nombre d'appels de méthode, et par appel de frais généraux n'est pas une priorité.

J'ai comparé les performances en écriture ne rien faire "nop" fonctionne comme les différents types de fonctions et de méthodes. Voici quelques résultats typiques.

>> call_nops
Ordinateur: PCWIN de presse: 2009b
Dans un appel de fonction/méthode 100000 fois
nop() fonction: 0.02261 sec 0.23 usec par appel
nop1-5() fonctions: 0.02182 s 0,22 usec par appel
nop() sous-fonction: 0.02244 s 0,22 usec par appel
@()[] fonction anonyme: 0.08461 sec 0.85 usec par appel
nop(obj) méthode: 0.24664 sec 2.47 usec par appel
nop1-5(obj) méthodes: 0.23469 sec 2.35 usec par appel
nop() fonction privée: 0.02197 s 0,22 usec par appel
classdef nop(obj): 0.90547 sec 9.05 usec par appel
classdef obj.nop(): 1.75522 sec 17.55 usec par appel
classdef private_nop(obj): 0.84738 sec 8.47 usec par appel
classdef nop(obj) (m-file): 0.90560 sec 9.06 usec par appel
classdef classe.staticnop(): 1.16361 sec 11.64 usec par appel
Java nop(): 2.43035 sec 24.30 usec par appel
Java static_nop(): 0.87682 sec 8.77 usec par appel
Java nop() de Java: 0.00014 sec 0.00 usec par appel
MEX mexnop(): 0.11409 sec 1.14 usec par appel
C nop(): 0.00001 sec 0.00 usec par appel

Des résultats similaires sur R2008a par R2009b. C'est sur Windows XP x64 cours d'exécution 32 bits MATLAB.

Le "Java nop()" est un méthode en Java appelée à partir de l'intérieur d'un M-code de la boucle, et comprend l'MATLAB-à-Java de répartition des frais généraux grâce à chaque appel. "Java nop() de Java" est la même chose appelé dans une Java boucle for() et ne pas occasionner de cette limite de pénalité. Prendre le Java et le C timings avec un grain de sel; un habile compilateur peut optimiser les appels par disparaître complètement.

Le paquet de portée mécanisme est nouveau, introduit à la même époque que le classdef classes. Son comportement peut être lié.

Quelques conclusions provisoires:

  • Les méthodes sont plus lents que les fonctions.
  • Nouveau style (classdef) les méthodes sont plus lents que les vieux style de méthodes.
  • Le nouveau obj.nop() syntaxe est plus lent que l' nop(obj) de la syntaxe, même pour la même méthode sur un classdef objet. De même pour les objets Java (non illustré). Si vous voulez aller vite, appelez - nop(obj).
  • Appel de la méthode de surcharge est plus élevée (environ 2x) en 64 bits MATLAB sous Windows. (Non présenté).
  • MATLAB répartition de méthode est plus lente que celle d'autres langues.

Le fait de dire pourquoi il en est ainsi serait juste de la spéculation de ma part. Le MATLAB du moteur OO internes ne sont pas publics. Il n'est pas interprété vs question compilé en soi - MATLAB dispose d'une équipe commune d'enquête - mais MATLAB looser de frappe et de syntaxe peut signifier plus de travail au moment de l'exécution. (E. g. vous ne pouvez pas dire à partir de la syntaxe ou du moins si, f(x)" est un appel de fonction ou d'un indice dans un tableau; elle dépend de l'état de l'espace de travail au moment de l'exécution.) Il est peut-être parce que MATLAB définitions de classe sont liés à système de fichiers de l'état en sorte que de nombreuses autres langues " ne le sont pas.

Alors, que faire?

Un idiomatiques MATLAB approche pour ce qui est de "vectoriser" votre code par la structuration de vos définitions de classe telle qu'une instance d'objet encapsule un tableau; c'est à chacun de ses champs de tenir des tableaux parallèles (appelé "planes" de l'organisation dans la documentation MATLAB). Plutôt que d'avoir un tableau d'objets, chacun avec des champs de portefeuille de valeurs scalaires, de définir des objets qui sont eux-mêmes des tableaux, et ont les méthodes prennent des tableaux d'entrées, et de faire vectorisé appels sur les champs et les entrées. Cela réduit le nombre d'appels de méthode faite, je l'espère assez que l'expédition de frais généraux n'est pas un goulot d'étranglement.

Imitant un C++ ou Java de la classe dans MATLAB ne sera probablement pas optimale. Java/C++ classes sont généralement construits tels que les objets sont les plus petits blocs de construction, aussi précis que vous le pouvez (qui est, beaucoup de classes différentes), et vous les composent dans des tableaux, objets de collection, etc, et itérer sur eux avec des boucles. Pour faire rapide MATLAB classes, tour qui approche à l'intérieur. Les classes sont plus grandes dont les champs sont des tableaux, et d'appeler vectorisé méthodes sur ces tableaux.

Le point est d'organiser votre code pour jouer sur les points forts de la langue - tableau de manutention, vectorisé mathématiques et d'éviter les points faibles.

EDIT: Depuis le post original, R2010b et R2011a viennent. L'ensemble de l'image est la même, avec le MCO des appels d'obtenir un peu plus vite, et Java et de style ancien appels de méthode arriver plus lent.

EDIT: j'ai utilisé quelques notes, ici, sur le "chemin de la sensibilité" avec une table supplémentaire d'appel de fonction timings, où les durées de fonctionnement ont été touchés par la façon dont le Matlab chemin a été configuré, mais qui semble avoir été une aberration de ma configuration réseau particulière à l'époque. Le graphique ci-dessus reflète la fois typique de la prépondérance de mes tests au fil du temps.

Mise À Jour: R2011b

EDIT (2/13/2012): R2011b et, à l'image de performances a suffisamment changé pour mettre à jour ce.

Arc: PCWIN de presse: 2011b 
Machine: R2011b, Windows XP, 8x Core i7-2600 @ 3.40 GHz, 3 GO de RAM, NVIDIA NVS 300
Chaque opération de 100000 fois
le style total µs par appel
nop() fonction: 0.16 0.01578
nop(), 10x déroulement des boucles: 0.15 0.01477
nop(), 100x déroulement des boucles: 0.15 0.01518
nop() sous-fonction: 0.16 0.01559
@()[] fonction anonyme: 0.64 0.06400
nop(obj) méthode: 0.28482 2.85
nop() fonction privée: 0.15 0.01505
classdef nop(obj): 4.33 0.43323
classdef obj.nop(): 0.81087 8.11
classdef private_nop(obj): 0.32272 3.23
classdef classe.staticnop(): 0.88959 de 8,90
classdef constante: 1.51890 15.19
classdef propriété: 0.12992 1.30
classdef propriété avec getter: 1.39912 13.99
+pkg.nop() fonction: 0.87345 8.73
+pkg.nop() à l'intérieur +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 de 5,25
Java Klass.static_nop(): 0.35357 3.54
Java obj.nop() de Java: 0.00010 0.00
MEX mexnop(): 0.08709 0.87
C nop(): 0.00001 0.00
j() (builtin): 0.03 0.00251

Je pense que le résultat de ceci est que:

  • MCO/classdef méthodes sont plus rapides. Le coût est maintenant à égalité avec les anciennes classes de style, aussi longtemps que vous utilisez l' foo(obj) de la syntaxe. Donc, la méthode de la vitesse n'est plus une raison de rester avec les anciennes classes de style dans la plupart des cas. (Bravo, MathWorks!)
  • Mettre des fonctions dans les espaces de noms les rend lent. (Pas nouvelle dans R2011b, tout nouveau dans mon test).

Mise À Jour: R2014a

J'ai reconstruit l'analyse comparative de code et l'exécuter sur R2014a.

Matlab R2014a sur PCWIN64 
Matlab 8.3.0.532 (R2014a) / Java 1.7.0_11 sur PCWIN64 Windows 7 6.1 (eilonwy-win7) 
Machine: Core i7-3615QM CPU @ 2.30 GHz, 4 GO de RAM (VMware Plate-forme Virtuelle)
nIters = 100000 

Temps de fonctionnement (µs) 
nop() fonction: 0.14 
nop() sous-fonction: 0.14 
@()[] fonction anonyme: 0.69 
nop(obj) méthode: 3.28 
nop() privé fcn sur @class: 0.14 
classdef nop(obj): 5.30 
classdef obj.nop(): 10.78 
classdef pivate_nop(obj): 4.88 
classdef classe.static_nop(): 11.81 
classdef constante: 4.18 
classdef propriété: 1.18 
classdef propriété avec getter: 19.26 
+pkg.nop() fonction: 4.03 
+pkg.nop() à l'intérieur +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() de Java: 0.01 
MEX mexnop(): 0.91 
builtin j(): 0.02 
struct s.foo domaine de l'accès: 0.14 
isempty(persistant): 0.00 

Le Code Source de Repères

J'ai mis le code source de ces critères sur GitHub, publié sous la Licence MIT. https://github.com/apjanke/matlab-bench

4voto

MikeEL Points 439

La classe de poignée possède une charge supplémentaire de suivi toutes références à lui-même à des fins de nettoyage.

Essayez la même expérience sans utiliser la classe poignée et voir quels sont vos résultats.

2voto

HG Bruce Points 1

OO performance dépend considérablement de la version MATLAB utilisée. Je ne peux pas commenter toutes les versions, mais sais par expérience que 2012 est que beaucoup améliorée des versions plus 2010. Aucun point de référence et donc pas de chiffres à présenter. Mon code, écrit exclusivement à l’aide de classes de poignée et sous 2012 ne fonctionnera pas du tout dans les versions antérieures.

1voto

Ahmad Points 1

En réalité aucun problème avec votre code, mais c'est un problème avec Matlab. Je pense qu'il est une sorte de jeu autour de ressembler. Il n'est rien que les frais généraux de compiler le code de la classe. J'ai fait le test avec simple de la classe point (une fois que la poignée) et l'autre (une fois que la valeur de la classe)

    classdef Pointh < handle
    properties
       X
       Y
    end  
    methods        
        function p = Pointh (x,y)
            p.X = x;
            p.Y = y;
        end        
        function  d = dist(p,p1)
            d = (p.X - p1.X)^2 + (p.Y - p1.Y)^2 ;
        end

    end
end

voici le test

%handle points 
ph = Pointh(1,2);
ph1 = Pointh(2,3);

%values  points 
p = Pointh(1,2);
p1 = Pointh(2,3);

% vector points
pa1 = [1 2 ];
pa2 = [2 3 ];

%Structur points 
Ps.X = 1;
Ps.Y = 2;
ps1.X = 2;
ps1.Y = 3;

N = 1000000;

tic
for i =1:N
    ph.dist(ph1);
end
t1 = toc

tic
for i =1:N
    p.dist(p1);
end
t2 = toc

tic
for i =1:N
    norm(pa1-pa2)^2;
end
t3 = toc

tic
for i =1:N
    (Ps.X-ps1.X)^2+(Ps.Y-ps1.Y)^2;
end
t4 = toc

Les résultats t1 =

12.0212 % de la Poignée

t2 =

12.0042 % de la valeur

t3 =

0.5489  % vector

t4 =

0.0707 % structure 

Donc pour une performance optimale et éviter d'utiliser la programmation orientée objet à la place de la structure est un bon choix pour les variables de groupe

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X