Dans une fonction MATLAB, le code suivant est utilisé:
function stuff()
if a == 2
do1();
else
do2();
end
end
Ce code est placé dans une boucle de simulation et est appelé 1000 fois ou plus par seconde. La déclaration if n'a d'importance que dans le premier appel de la fonction, après que soit do1 ou do2 soit utilisé, la variable a ne changera plus.
Comment éviter de perdre du temps de traitement avec cette déclaration if ? Fondamentalement, comment dire à Matlab, de ne plus vérifier l'instruction if, et d'appeler simplement la fonction unique, qui est sélectionnée lors du premier appel à stuff?
3 Réponses :
Je pense que vous ne perdez pas beaucoup de temps à vérifier la validité de cette déclaration if . Cependant, puisque vous le mentionnez spécifiquement, il ne vérifie que la première itération: pourquoi ne pas le sortir? Donc au lieu de:
k = 1;
for ii = 2:10
k = k + 1;
end
Vous pourriez faire
for ii = 1:10
if ii == 1
k = 1;
else
k = k + 1;
end
end
Éliminant ainsi le contrôle.
NB: cela évolue mal bien sûr, mais comme il ne s'agit ici que d'une seule itération, je considère que c'est une bonne option.
Mais comment dire à MATLAB alors qu'il doit appeler une fonction spécifique ( do1 ou do2 ) à partir de maintenant?
@Lemonbonbon vous recevez d'abord l'appel à do1 , puis passez en boucle sur do2 . Au moins, je suppose que vous allez faire une boucle, car vous n'avez pas montré comment a s'incrémente. L'idée reste la même: faites d'abord l'appel unique, puis faites le reste par la suite. S'il est très compliqué de le sortir, vous pouvez même écrire deux fonctions: l'une autour de do1 () , et l'autre autour de do2 () et vous pouvez le faire comme décrit ici.
Oh, ma question n'était peut-être pas assez claire. Je ne sais pas que la météo do1 ou do2 est utilisée dans la boucle. Cette décision est évaluée lors du premier appel à trucs. Après cela, do1 OU do2 sont appelés pour le reste de la simulation.
@Lemonbonbon: Le problème est que vous avez décrit votre code au lieu de montrer votre code. Montrer c'est toujours mieux, cela évite les malentendus. Voir l ' exemple minimal reproductible .
Compte tenu des commentaires ci-dessus, il semble que vous cherchiez réellement un moyen de choisir dynamiquement la fonction à exécuter dans votre simulation. Ce choix doit être dynamique (vous ne savez pas quelle fonction utiliser à l'exécution) mais le choix ne doit être fait qu'une seule fois. Ceci est facilement réalisable en utilisant des poignées de fonction: https://www.mathworks.com/ help / matlab / function-handles.html
Voici un exemple:
function dynamicSimulation()
if ( rand() > 0.5 ) % determine which function should be called dynamically
sim=@func1;
else
sim=@func2;
end
other_params = [];
for k = 1:5 % run the simulation
sim( k, other_params );
end
end
function func1( index, other_params )
fprintf( 'Index=%d: Simulating using function 1\n', index );
end
function func2( index, other_params )
fprintf( 'Index=%d: Simulating using function 2\n', index );
end
Si vous exécutez ceci plusieurs fois, vous remarquerez que le (aléatoire) le choix de func1 ou func2 signifie que vous n'obtiendrez pas la même fonction exécutée à chaque fois, bien que la même fonction soit utilisée pour toute la simulation.
La surcharge de la poignée de fonction est-elle plus grande ou plus petite que la surcharge d'une instruction if ?
Cela semble être une bonne solution (de par sa conception), mais je suis vraiment intéressé par le temps que cela prend par rapport à l'instruction if. En outre, le code doit être utilisable pour la génération de code. Les poignées de fonction sont-elles possibles avec la génération de code? Autant que je sache, tout ce qui utilise ce truc (POO, etc.) n'est pas compatible avec CG.
@Lemonbonbon la différence de timing n'est mesurable que par vous, puisque vous êtes le seul à avoir le code d'origine. Exécutez simplement le profileur en utilisant les deux versions et vous le saurez assez tôt. La question de savoir si les poignées de fonction fonctionnent avec la génération de code est une question totalement différente et doit être posée séparément.
J'ai fait un petit test pour comparer le temps total d'appel d'une fonction dans une boucle de trois manières: 1. Directement 2. Poignée de fonction 3. Appelez une fonction similaire mais avec une instruction if - else. Les résultats ont montré un impact marginal sur le temps du if-else et un impact significatif de l'utilisation d'un descripteur de fonction. C'est pourquoi je n'ai pas posté cela comme réponse.
rejoindre un peu tard: merci @EliahuAaron pour avoir fait le benchmark, et je suis d'accord avec Adriaan, votre kilométrage peut varier en fonction de votre cas d'utilisation spécifique. Je suppose que les poignées de fonction ressemblent beaucoup à des pointeurs de fonction, donc peu de frais généraux attendus, mais je ne le sais pas vraiment. En ce qui concerne la génération de code, veuillez passer par le lien que j'ai mentionné re: handles, vous trouverez la fonction str2func qui pourrait répondre à vos besoins.
@Lemonbonbon: Quant à la question de savoir si les poignées de fonctions fonctionnent avec la génération de code: c'est facile à tester. Tout ce que vous avez à faire est de copier-coller la fonction écrite dans cette réponse et d'essayer de lui appliquer la génération de code. Puisque vous avez accès à la boîte à outils de génération de code, c'est probablement plus facile pour vous de tester que pour n'importe lequel d'entre nous qui n'a pas accès à cette boîte à outils.
Contrairement à ce que vous croyez, ce n'est pas un problème, le compilateur (devrait) faire automatiquement cette optimisation pour vous. Voir par exemple Mouvement de code invariant en boucle .
Ce que vous pouvez faire pour aider le compilateur est de déplacer le calcul de la vérification à l'extérieur comme un drapeau, par exemple
flag = a==2;
for i = 1:100
stuff(flag)
end
Ensuite, vous n'avez à faire le calcul qu'une seule fois et il est clair pour le compilateur que la valeur ne change pas.
NOTE: De toute évidence, si votre vérification est vraiment a == 2 , cela ne ferait pas beaucoup de différence.
MODIFIER: Je n'ai pas été en mesure de vérifier avec certitude que MATLAB le fait automatiquement. Cependant, ce n'est que la première couche d'optimisation qui est faite pour vous. Tous les processeurs modernes utilisent ce qu'on appelle un prédicteur de branche, voir par ex. cette réponse brillante Pourquoi traite un tri tableau plus rapide que le traitement d'un tableau non trié? , ou cette page wiki . En bref, le processeur devine le résultat de l'instruction if, s'il est correct, tout va plus vite. Je pense qu'il est juste de dire que le processeur devine correctement dans tous vos cas.
TLDR: Ne vous en faites pas.
Bien placé. Ma première pensée a aussi été pourquoi m'inquiéter.
Intéressant! @Lemonbonbon, je vous suggère d'essayer ceci et de revenir vers nous. Vous pourriez avoir les deux fonctions en fait être les mêmes (afin qu'elles aient les mêmes temps de calcul), puis voir si l'exécution de la boucle avec le if est significativement plus lente que la boucle avec seulement 1 fonction? Afin de ne pas déclencher "l'invariation de boucle", les deux fonctions devraient en fait être légèrement différentes pour éviter qu'elles soient vues comme le même code, si je comprends bien ...
Avant d'optimiser, j'exécutais le [profiler] ( mathworks.com/help/matlab /ref/profile.html ) pour vérifier si l'instruction
ifprend trop de temps. De quoi dépenda? Le résultat detrucs? En fonction de l'endroit / de ce que vous devez comparer, vous pouvez également passer le bon descripteur de fonction àstuff.Vous pouvez utiliser un descripteur de fonction qui pointe vers
do1 ()oudo2 ()et définir le descripteur de fonction une fois, de cette façon, vous n'avez pas besoin de savoir à l'avance quelle fonction à appeler. Mais, l'utilisation d'un descripteur de fonction peut coûter plus cher en performances qu'une instructionif...Étant donné que votre code fonctionne et que vous essayez simplement d'améliorer les performances, vous pouvez trouver une aide supplémentaire en déplaçant la question vers Révision du code