I. Introduction▲
Nous allons voir dans cet article que le temps d'exécution d'un code Python peut parfois être relativement long et qu'il existe différentes manières pour y remédier.
Cet article n'a pas pour but d'expliquer en détail comment le développeur peut faire ceci. Il s'agit juste ici d'une simple présentation associée à une comparaison avec les performances d'un code écrit en C++.
Comme code exemple nous choisirons celui du plus grand diviseur commun entre deux nombres.
Pour ce faire nous réaliserons ce code dans les configurations suivantes :
- en pur Python ;
- en Cython ;
- en QML appelé par Python ;
- en QML appelé par Cython ;
- en QML appelé par C++ ;
- en pur C++ ;
Comme vu plus haut, le but de cet article n'est pas d'expliquer comment sont créés les codes, mais uniquement de faire les tests nécessaires. Ne cherchez donc pas ici un tutoriel sur le langage Cython ou QML par exemple.
II. Création des codes▲
Ci-dessous vous trouverez les différentes versions du code que nous utiliserons. Afin d'augmenter volontairement le temps d'exécution nous allons faire en sorte de répéter l'opération plusieurs centaines de fois.
II-A. Code Python▲
def fonction(a,b):
while b != 0:
a,b=b,a%b
return a
for i in range(0,10000001):
fonction(9078,5118)
print("fin du test i = ", i)
II-B. Code Cython▲
cpdef fonction(a,b):
while b != 0:
a,b=b,a%b
return a
for i in range(0,10000001):
fonction(9078,5118)
print("fin du test i = ", i)
II-C. Code QML + divers appels▲
II-C-1. Code QML▲
import QtQuick 2.0
Item {
function myTest(){
function pgcd(a, b){
return b ? pgcd(b, a % b) : a
}
for (var i=0; i<=10000000; i=i+1){
pgcd(9078, 5118)
}
console.log("Fin du test i = ", i)
return 0
}
}
II-C-2. Appel via Python▲
import sys
from PyQt5.QtCore import QCoreApplication, QUrl, QMetaObject, Qt
from PyQt5.QtQml import QQmlComponent, QQmlEngine
def fonction():
app = QCoreApplication(sys.argv)
engine = QQmlEngine()
component = QQmlComponent(engine)
component.loadUrl(QUrl('ex.qml'))
test = component.create()
QMetaObject.invokeMethod(test, "myTest", Qt.DirectConnection)
del engine
fonction()
II-C-3. Appel via Cython▲
import sys
from PyQt5.QtCore import QCoreApplication, QUrl, QMetaObject, Qt
from PyQt5.QtQml import QQmlComponent, QQmlEngine
cpdef fonction():
app = QCoreApplication(sys.argv)
engine = QQmlEngine()
component = QQmlComponent(engine)
component.loadUrl(QUrl('ex.qml'))
test = component.create()
QMetaObject.invokeMethod(test, "myTest", Qt.DirectConnection)
del engine
fonction()
II-C-4. Appel via C++▲
#include <QApplication>
#include <QQmlEngine>
#include <QQmlComponent>
#include <QQuickView>
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("ex.qml"));
QObject *object = component.create();
QMetaObject::invokeMethod(object, "myTest", Qt::DirectConnection);
return app.exec();
delete object;
}
II-D. Code C++▲
#include <stdio.h>
int pgcd(int a, int b)
{
return b ? pgcd(b, a % b) : a;
}
int main(void)
{
for (int i=0; i<=10000000; i=i+1);
pgcd(9078, 5118);
printf("Fin du test i = 10000000");
return 0;
}
Voila, tous nos codes sont écrits. Pour ceux utilisant Cython ou C++ une compilation complémentaire est nécessaire. Je vous invite pour cela à lire les différentes documentations présentes sur developpez.com.
Nous allons pouvoir maintenant passer aux tests.
III. Tests des codes créés▲
Pour les utilisateurs linux, je vous propose de créer un bash permettant de faire nos tests. Au moment de rédiger cet article, je n'ai pas la possibilité de faire des tests sur d'autres OS mais je présume qu'il est possible de faire quelque chose de similaire à ce qui va suivre.
Voici le bash proposé :
echo
echo "==========================================="
echo "Temps exécution en Python :"
time python3 codepython.py
echo
echo "==========================================="
echo "Temps exécution en Cython:"
time python3 lancecython.py
echo
echo "==========================================="
echo "Temps exécution en QML appelé via Python :"
time python3 qmlviapython.py
echo
echo "==========================================="
echo "Temps exécution en QML appelé via Cython :"
time python3 lanceqml.py
echo
echo "==========================================="
echo "Temps exécution en C++ :"
time ./codecpp
echo
echo "==========================================="
echo "Temps exécution en QML appelé via C++ :"
time ./qmlviacpp
Il ne reste plus qu'à lancer lance.sh via la commande et à constater les résultats :
./lance.sh
Voici dans mon cas le résultat obtenu :

On pourra remarquer plusieurs choses :
- le code Python est vraiment long ce qui peut obliger le développeur à utiliser plusieurs threads s'il ne veut pas figer sont programme lors de certains calculs ;
- le code Cython permet un gain d'environ 50 % par rapport au code Python, ce qui peut être assez sympa puisque beaucoup de code peuvent être transcrit rapidement. Cependant ceci nécessite le passage par une compilation ;
- le code QML lancé par Python ou Cython est environ identique en termes de temps d'exécution, par contre cette manière permet de gagner beaucoup par rapport au code Python. On peut en déduire que des fonctions écrite en QML seront plus rapidement exécuter que des fonctions Python ;
- le code QML lancé par C++ est plus long que le même lancé via Python mais demeure plus rapide que du pur Python ;
- le code C++ écrase tout est reste le code le plus rapide en termes d'exécution.
IV. Conclusion▲
J'utilise depuis quelque temps PyQt, mais est découvert que très récemment Qt Quick. Ces simples tests m'ont permis de mettre le doigt sur un point important : il est très certainement plus intéressant de coder un maximum de chose en QML, celui-ci permettant un net gain de performance sans même devoir utiliser Cython.
V. Remerciements▲
Je tiens à remercier tout particulièrement …. et …. pour leur relecture attentive.




