Comparaison AutoIt – C++
Remarques générales sur les autres langages
Tout ce qui est décrit ici pour le C++ s’applique pour l’essentiel au C# et au Java. Et dans une moindre mesure au VB (qui est un peu à mi-chemin entre AutoIt et C++). On peut considérer très schématiquement que le C++ sera plus performant (en terme de vitesse) que le C# ou le Java (langage compilé vs semi-interprété), mais c’est rarement perceptible dans l’application finale. A l’opposé, le Java et le C# constituent des « améliorations » du C++, en faisant des langages en principe de plus haut niveau. Le C# est un langage conçu par Microsoft (c’est le « Java-killer » de Microsoft) et poussant très loin la génération automatique du code. Ainsi, c’est très simple avec un tel langage de s’interfacer avec une base de données, ou encore de réaliser une application réseau. On aime ou on n’aime pas, mais cela ne laisse généralement pas indifférent.
Le Java est surtout apprécié pour sa portabilité, et utilisé essentiellement sur les applications Internet (aussi bien du côté serveur que client).
A noter que la syntaxe des langages C++, C# et Java est très proche.
Simplicité de prise en main
Avantage très net à AutoIt.
On retrouve tous les avantages – en terme de simplicité – d’un langage de type « BASIC » :
o on commence le code « utile » dès la première ligne du fichier
o pas nécessaire de déclarer les variables et les variables sont non typées
o langage interprété (pas d’étape de compilation pour tester le script)
o Indentation libre, pas de caractère de fin de ligne…
Quand à lui, le C++ est plus ardu d’accès.
• De plus, il y a « le » C++, et ensuite tous les « dialectes » qui s’y greffe et viennent enrichir le C++. Il faut comprendre que dans les langages informatiques modernes, c’est bien moins la maîtrise du langage proprement dit qui prend du temps que la connaissance de toutes les librairies qui gravitent autour.
• Les outils tels que Visual Studio permettent cependant de simplifier considérablement la prise en main du C++, notamment en générant automatiquement le squelette de l’application (en fonction des choix à la création d’un nouveau projet).
Temps de développement pour un programme simple
Avantage très net à AutoIt (à moins d’une base solide et complète en C++)
o Par exemple, pour faire un « bot » ultra-rudimentaire qui va cliquer sur un pixel d’une couleur donnée, c’est très simple à faire en Autoit.
Deux lignes suffisent :
Cliquez pour révéler
Cliquez pour masquer
$coord = PixelSearch(0,0,1023,767,"0xF9E243")
MouseClick("left", $coord[0], $coord[1])
o La version en C++ est tout de suite beaucoup plus compliquée, et – paradoxalement – bien moins efficace si on s’en tient au code le plus simple possible (basé sur l’utilisation de GetPixel alors que AutoIt propose maintenant une fonction de recherche optimisée - PixelSearch). Par contre, dans le cadre d’un projet de bot significatif, un développeur C++ qui se respecte commencera par développer (ou dénicher) une bibliothèque de fonctions optimisées pour toutes les fonctions de base dont il aura besoin, et alors la version en C++ devient beaucoup plus simple et surtout performante.
A noter que l’exemple ci-dessous ne compilera éventuellement pas (tout dépend du contenu de stdafx.h, des options de compilation…).
Cliquez pour révéler
Cliquez pour masquer
#include "stdafx.h"
CPoint PixelSearch(int X1, int Y1, int X2, int Y2, COLORREF color)
{
int x, y;
CDC *pDC = CWnd::GetDesktopWindow()->GetDC();
for (x=X1; x<=X2; x++)
for (y=Y1; y<=Y2; y++)
if (pDC->GetPixel(x,y)==color)
return CPoint(x,y);
return CPoint(0,0); // Position par défaut au cas où la couleur demandée n'est pas trouvée
}
void MouseLeftClick(CPoint &Pos)
{
mouse_event(MOUSEEVENTF_LEFTDOWN, Pos.x, Pos.y, 0, NULL);
Sleep(10);
mouse_event(MOUSEEVENTF_LEFTUP, Pos.x, Pos.y, 0, NULL);
}
int main()
{
CPoint Coord = PixelSearch(0, 0, 1023, 767, RGB(0xF9, 0xE2, 0x43));
MouseLeftClick(Coord);
}
Réutilisabilité des « briques » logicielles
Avantage au C++
Certes, on constate qu’une communauté impressionnante développe des UDF pour Autoit, permettant de combler ses lacunes et repousser ses limites.
Mais la simplicité même du langage, l’absence de typage des variables, l’impossibilité de hiérarchiser le code, et surtout le fait que Autoit ne soit pas un « langage objet » limitent sérieusement la possibilité de conserver des briques d’un projet à un autre.
En C++, c’est beaucoup plus facile, dès lors que l’on respecte quelques règles élémentaires (bien encapsuler les objets, nommage cohérent des fichiers sources, commentaires ou documentation du code…).
Temps de développement pour un programme complexe
Avantage net au C++ (avec un IDE moderne).
J’aurai du mal à vous l’expliquer simplement, aussi sur ce point je vous demande de me croire sur parole :p Que ce soit au niveau de l’approche objet, des automatismes apportés par les environnements modernes (MSVC dans mon cas), le debuggage.
Lisibilité et réutilisabilité du code
Avantage net au C++
La déclaration et le typage strict des variables aide également grandement à avoir un code propre et lisible. Les données structurées apportent aussi une visibilité correcte.
La définition d’objets permet de hiérarchiser le code, en s’attaquant déjà aux briques élémentaires avant de les assembler.
Dans Autoit, il n’y a que la notion de fonction. C’est bien pour quelques dizaines ou centaines de lignes. Mais ça devient inextricable à partir de quelques milliers de lignes de code. En s’imposant des règles strictes on peut un peu repousser les limites d’utilisation de ce langage (indentation, découpage judicieux en fichiers, nommage rigoureux des variables et fonctions…), mais cette limite fait qu’au-delà d’un certain seuil, on perd en efficacité et on finit par ne plus avancer.
Ainsi dans l’exemple simple au-dessus, on voit que la variable $coord est en fait un tableau d’une dimension, contenant les coordonnées (deux données donc de type entier), l’abscisse étant dans $coord[0], l’ordonnée dans $coord[1]. Mais rien ne le dit. Il faut bien connaitre la fonction PixelSearch pour savoir quel type de données elle renvoie, et utiliser de façon appropriée la variable ainsi initialisée. A l’opposé, dans l’exemple en C++, on doit utiliser une variable du type approprié (ici une structure de type Point, qui est composée de deux entiers X et Y). On sait donc ce que l’on manipule, et il n’y a aucune ambigüité.
Possibilités de debuggage
Avantage net au C++.
Ceux qui n'ont jamais vraiment développé d'applications complexes ne peuvent se rendre compte de l'importance de ce point. Et pourtant, quand l'application devient complexe, si vous êtes vraiment exigents vous passerez bien plus de temps dans le debugger à comprendre ce qui ne va pas qu'à vraiment écrire des lignes de code. C'est pourquoi ce point devient rapidement très très important. Et le petit debugger graphique proposé dans Autoit ne saurait rivaliser avec les possibilités d'un environnement comme Visual Studio 2010.
Richesse du langage
Avantage au C++.
En gros, les deux environnements sont également riches. Si en natif un outil comme le Visual C++ dispose d’une richesse fonctionnelle bien plus grande, les nombreuses UDF dispo dans Autoit ont sensiblement comblé les vides. La grande force d’Autoit pour accéder à tout ce qui n’existe pas en natif, c’est la possibilité d’accéder à n’importe quelle fonction implémentée dans un DLL (fonction DllCall). Cela permet notamment d’écrire une routine optimisée en C par exemple et l’appeler depuis un script Autoit.
Pourtant, si en théorie on peut quasiment tout faire en Autoit, dans les faits on constate très rapidement ses limites (en terme de complexité, performance, maintenabilité...).
Performance / Vitesse d’exécution
Avantage net au C++
Cependant, il faut relativiser cet avantage. Car dans la majorité des cas, le PC est suffisamment puissant pour que les traitements soient quasi-instantanés. Et souvent, l’optimisation de l’algorithme est bien plus important que l’utilisation d’outils de développement optimisés en vitesse.
Benchmarks
Pour montrer le gain en vitesse en passant au C++, j'ai comparé le temps d'exécution de 4 bouts de code écrit en Autoit et en C++.
Détail de la configuration de test
Cliquez pour révéler
Cliquez pour masquer
Pour AutoIt, il s'agit de la version 3.3.6.1; pour le C++, il s'agit de Visual Studio 2010 (en mode non managé).
Configuration utilisée : c'est une machine moyenne datant de 3 ans environ.
OS : Vista Entreprise sp2,
RAM : 2Go RAM,
CPU : dual core E6550 @ 2.33GHz.
Comme tous ces tests sont réalisés sur un seul thread, un seul coeur est utilisé (donc peu importe que le CPU soit dual ou quad core, ça ne changera pas grand chose sur ce type de programmes).
Dans le cas du C++, il faut savoir que les optimisations propres au compilateur permettent des gains de temps encore plus importants, aussi, pour comparer, j'ai également relevé les temps en désactivant toute optimisation du compilateur.
Exemple N°1
Il s'agit d'une boucle incrémentant simplement une variable (entier) 10 000 000 de fois.
Autoit
Cliquez pour révéler
Cliquez pour masquer
$begin = TimerInit()
$a = 1
$b = $a
for $x = 0 to 10000000
$a += 1
Next
$dif = TimerDiff($begin)
MsgBox(0, "Durée pour 10 000 000 occurences d'une boucle presque vide", $dif)
C++
Cliquez pour révéler
Cliquez pour masquer
int i=0;
for (int j=0; j<10000000; j++)
i++;
Résultats :
Autoit : 3.07 secondes
C++ : 0 !!
C++ avec compilateur non optimisé : 0.023 secondes
Comment est-ce possible d'avoir 0 en C++ me direz-vous ? En réalité, c'est à peine une nano-seconde (0.000000001 secondes). La raison est simple : le compilateur est suffisamment astucieux pour se rendre compte qu'il ne sert à rien d'incrémenter 10 000 000 de fois une même variable, et il va remplacer ce code par un code donnant le même résultat mais bien plus rapide. Ainsi, ce qui est réellement généré en assembleur par le compilateur ressemble plus à :
i = 10000000;
Exemple N°2
Ici on fait des calculs un peu plus conséquents, toujours 10 000 000 de fois.
Autoit
Cliquez pour révéler
Cliquez pour masquer
$begin = TimerInit()
$a = 1
$b = $a
for $x = 0 to 10000000
$a += 1
$b = $a + $b
if ($b>54321) then $b /= 2;
Next
$dif = TimerDiff($begin)
MsgBox(0, "Durée pour 10 000 000 occurences d'une boucle presque vide", $dif)
C++L'équivalent en C++ (pour simplifier cet exposé, seule la partie importante du code est reprise).
Cliquez pour révéler
Cliquez pour masquer
int a = 0,
b = a;
for (int j=0; j<100000000; j++)
{
a++;
b = a+b;
if (b>54321) b /= 2;
}
Autoit : 33.68 secondes
C++ : 0.0218 secondes
C++ avec compilateur non optimisé : 0.0686 secondes
Exemple N°3
Là on complique encore un peu, en déclarant 2 fonctions imbriquées, appelées toujours dans une boucle 10000000 de fois.
Constat intéressant (j'avais un doute), que les fonction soient dans le même fichier ou dans un include séparé ne change en rien la vitesse d'execution dans Autoit. Cela permet d'en conclure qu'il s'agit vraisemblablement d'un language semi-interprété, le script étant entièrement compilé au chargement.
Autoit
Cliquez pour révéler
Cliquez pour masquer
Func swap(ByRef $a, ByRef $b) ;swap the contents of two variables
Local $t
$t = $a
$a = $b
$b = $t
EndFunc
Func toto($a, $b)
swap($a,$b)
$c = $a + 2*$b
$c += 12
if ($c>100000) then $c = 2
return $c
EndFunc
$a = 1
$b = $a
for $x = 0 to 1000000
$a += 1
$b = $a + $b
if ($b>54321) then $b /= 2
$b = toto($a, $b)
Next
C++
Cliquez pour révéler
Cliquez pour masquer
void swap(int &a, int &b) //swap the contents of two variables
{
int t;
t = a;
a = b;
b = t;
}
int toto(int a, int b)
{
swap(a,b);
int c = a + 2*b;
c += 12;
if (c>100000) c = 2;
return c;
}
int main()
{
int a = 0,
b = a;
for (int j=0; j<10000000; j++)
{
a++;
b = a+b;
if (b>54321) b /= 2;
b = toto(a,b);
}
return 0;
}
Autoit : 204.4 secondes
C++ : 0.219 secondes
C++ avec compilateur non optimisé : 1.87 secondes
Exemple 4
Et enfin ce dernier exemple montre l'appel à une fonction de l'API Windows qui est assez longue à s'executer: GetPixel (renommée PixelGetColor en Autoit). Cette fois-ci, on ne fait tourner la boucle que 1024 fois, car ce serait trop long sinon.
Autoit
Cliquez pour révéler
Cliquez pour masquer
for $x = 0 to 1023
PixelGetColor($x, 200)
Next
C++
Cliquez pour révéler
Cliquez pour masquer
CDC *pDC = CWnd::GetDesktopWindow()->GetDC();
for (int x=0; x<1024; x++)
pDC->GetPixel(x,200);
Autoit : 18.7 secondes
C++ : 17.2 secondes !!
C++ avec compilateur non optimisé : 17.3 secondes
PixelSearch vs PixelGetColor
Cliquez pour révéler
Cliquez pour masquer
J'ai fait des essais comparatifs entre les 3 opérations :
- PixelGetcolor (renvoie donc la couleur d'un pixel unique)
- PixelSearch sur une zone d'un seul pixel (similaire à PixelGetColor au niveau fonctionnel dans bien des cas)
- PixelSearch sur une zone de 300 x 300 pixels
Et le résultat peut paraitre pour le moins étonnant : dans les trois cas, il faut environ 8.7 secondes pour 500 occurences. Donc il ne faut pas hésiter à utiliser l'instruction PixelSearch, car cette fonction est très bien optimisée comparativement au PixelGetColor.
Analyse des résultats du benchmark
On constate qu'un programme en c++ est très significativement plus rapide qu'en AutoIt. Ainsi dans le développement d'algorithmes complexe, le gain en vitesse est de l'ordre de 1000 fois plus rapide. Concrètement, cela signifie qu'un code mettant 10 minutes en AutoIt mettra moins d'une seconde en C++.
Par contre, si vous appelez des fonctions de haut niveau (API Windows par exemple) qui prennent pas mal de temps à s'executer (comme ici GetPixel, qui prend environ 17 ms), alors ce temps sera quasiment le même quel que soit le langage utilisé.
Donc, le gain effectif en vitesse dépendra de l'application que vous développez. Si vous effectuez beaucoup d'opérations simples comme des calculs avec des boucles, alors le gain sera très sensible. Si à l'opposé vous faîtes surtout des opérations assez lourdes (accès réseau, primitives graphiques, manipulations de fichiers...), alors le gain sera plus limité.
Conclusion
Comme cela a été suggéré à maintes reprises sans être vraiment argumenté, AutoIt + SCIte Script Editor constitue un environnement très sympa pour une première approche de la programmation. Certains pédagogues considèrent que ces langages "anarchiques" donnent de bien mauvaises habitudes de programmation, et qu'il est très difficile de s'en défaire par la suite. C'est pas faux. Mais ce qui est le plus important, c'est d'apprendre à convertir une idée en algorithme puis en code. Et pour cet apprentissage là, Autoit convient parfaitement. Cerise sur le gateau, ce langage est gratuit.
Par contre, si vraiment vous accrochez et que vous vous sentez limité par Autoit, il faut arriver à rapidement sauter le pas et passer à un langage type C++/C# ou Java. Ce sont les langages les plus utilisés dans le monde industriel (avec le C, l'ancêtre du C++), et ce n'est pas sans raisons. Vous pouvez toujours couper la poire en deux et en rester à un langage comme le VB.