Twisted est un framework event-driven de création d'applications et de serveurs internet en Python. Découvrez tout ce que vous devez savoir sur cet outil très utilisé : origines, histoire, fonctionnement, formations...
Au début des années 2000, les créateurs de jeux vidéo en réseau n’avaient aucune bibliothèque de langage de programmation multiplateforme à disposition.
C’est à cette époque que le programmeur américain Glyph Lefkowitz travaillait sur un jeu multijoueur basé sur du texte et intitulé Twisted Reality. Très rapidement, le projet a pris une tournure chaotique. Pour chaque connexion, trois threads Java étaient requis.
Un thread servant aux entrées bloquait sur les lectures, un thread pour la sortie bloquait sur certains types d’écriture, et un thread de « logique » dormait en attendant l’expiration des timers ou l’ajout d’événements à la queue.
Lorsque les joueurs naviguaient dans cet environnement virtuel et interagissaient, les threads entraient en interblocage, les caches étaient corrompus, et la logique de blocage n’était jamais appropriée.
En d’autres termes : l’usage de threads rendait le logiciel compliqué, buggé et très difficile à étendre. Face à ces problèmes, Glyph a pris conscience du besoin d’un framework de networking extensible, multiplateforme et event-driven.
L'histoire de Twisted
En cherchant des solutions aux problèmes rencontrés lors du développement de son jeu, Glyph a découvert Python et son module « select » pour le multiplexage I/O à partir d’objets flux tels que des sockets ou des tuyaux.
À l’époque, Java n’exposait pas l’interface select du système d’exploitation ou une autre API I/O asynchrone. Le package java.nio pour l’I/O non-blocante fut ajouté en 2002 avec J2SE 1.4.
Ainsi, un prototype rapide du jeu en Python utilisant le module select s’avéra immédiatement moins complexe et plus fiable que la version threadée.
Dès lors, Glyph écrivit un client et un serveur pour son jeu en Python à l’aide de l’API select. Toutefois, il voulait aller plus loin et être capable de transformer l’activité réseau en appels de méthode sur les objets dans le jeu.
Il imaginait notamment la possibilité de recevoir un email dans le jeu, à l’instar du mail daemon du jeu NetHack de 1987. Ou encore la possibilité pour chaque joueur d’avoir une page d’accueil.
Pour concrétiser ses idées, Glyph avait besoin de clients et serveurs HTTP et IMAP Python utilisant select. Il essaya d’abord la plateforme Medusa, développée au milieu des années 90 pour l’écriture de serveurs de mise en réseau en Python basés sur le module « asyncore ».
Ce module est un gestionnaire de socket permettant de construire un répartiteur et une interface de rappel par-dessus l’API select du système d’exploitation. Toutefois, Medusa avait deux points faibles.
D’abord, l’abandon de ce projet était prévu pour 2001. En outre, le module asyncore est un wrapper si fin autour des sockets que les programmeurs d’application doivent encore manipuler les sockets directement.
La portabilité est donc encore la responsabilité du programmeur. De plus, la prise en charge d’asyncore par Windows était encore buggée et Glyph savait qu’il voulait exécuter un client GUI sur Windows.
Face à la perspective d’implémenter une plateforme de mise en réseau lui-même, Glyph réalisa que Twisted Reality avait ouvert la porte à un problème aussi intéressant que le jeu en lui-même. Au fil du temps, son projet de jeu vidéo muta en une plateforme de mise en réseau : Twisted.
Qu'est-ce que Twisted ?
Twisted est un moteur de mise en réseau « event-driven » écrit en langage Python. On l’utilise notamment pour créer des serveurs ssh, proxy, SMTP et HTTP.
Cet outil corrige plusieurs faiblesses des plateformes de networking en Python existantes auparavant. Il utilise la programmation even-driven plutôt que la programmation multi-threaded. C’est également un outil multiplateformes offrant une interface uniforme pour les systèmes de notification d’événement exposés par les principaux systèmes d’exploitation.
En outre, Twisted fournit directement des implémentations client et serveurs de nombreux protocoles de couche application et transport dont TCP, UDP, SSL/TLS, HTTP, IMAP, SSH, IRC et FTP. Des utilitaires permettent aussi de configurer et déployer facilement les applications à partir de l’invite de commande. Il est donc immédiatement utile pour les développeurs.
C’est également un outil conforme aux RFCs (Request for Comments) prouvant sa conformité par une solide suite de tests. Il est extensible, et simplifie l’utilisation de multiples protocoles de mise en réseau.
from twisted.web import server, resource
from twisted.internet import reactor, endpoints
class Counter(resource.Resource):
isLeaf = True
numberRequests = 0
def render_GET(self, request):
self.numberRequests += 1
request.setHeader(b"content-type", b"text/plain")
content = u"I am request #{}\n".format(self.numberRequests)
return content.encode("ascii")
endpoints.serverFromString(reactor, "tcp:8080").listen(server.Site(Counter()))
reactor.run()
Qu'est-ce que la programmation event-driven ?
La principale caractéristique de Twisted est qu’il s’agit d’un moteur de mise en réseau event-driven (dirigée par les événements). Ce paradigme de programmation consiste à déterminer le flux du programme par les événements extérieurs.
Il est caractérisé par une boucle d’événement et l’utilisation de rappels pour déclencher des actions lorsque les événements surviennent. Parmi les autres paradigmes les plus communs, on compte la programmation mono-thread synchrone et la programmation multi-thread.
Un programme synchrone mono-thread effectue les tâches en série. Si une tâche bloque pendant un moment sur I/O (input/output), toutes les autres tâches doivent patienter jusqu’à ce qu’elle soit terminée pour être exécutées à leur tour.
Cet ordre défini et ce traitement en série simplifient le raisonnement, mais le programme est inutilement lent si les tâches ne dépendent pas l’une de l’autre. Pour cause, elles devront malgré tout s’attendre mutuellement.
De son côté, un programme multi-thread effectue les tâches dans des threads de contrôle séparées. Ces threads sont gérés par le système d’exploitation et peuvent être exécutées simultanément sur de multiples processeurs ou entrelacées sur un processeur unique.
Ceci permet à des threads de progresser même lorsque les autres bloquent sur des ressources. En général, cette approche permet de gagner du temps par rapport à un programme synchrone analogue.
Toutefois, il est nécessaire d’écrire du code pour protéger les ressources partagées pouvant être exploitées simultanément par de multiples threads. Les programmes multi-threads requièrent un raisonnement plus complexe, puisqu’il est impératif de se préoccuper de la sécurité du thread par la sérialisation de processus, la réentrance, le stockage thread-local ou d’autres mécanismes. En cas de mauvaise implémentation, des bugs subtils peuvent survenir.
Enfin, un programme event-driven entrelace l’exécution des tâches dans un thread de contrôle unique. Lors de l’I/O ou d’autres opérations exigeantes, un rappel est enregistré avec une boucle d’événement et l’exécution continue pendant que l’opération se termine.
Le rappel décrit comment prendre en charge un événement après sa complétion. La boucle d’événement interroge les événements et les répartit entre les rappels au fil du leur arrivée.
Ceci permet au programme d’effectuer des progrès quand il peut sans avoir à utiliser de threads additionnels. Les programmes event-driven simplifient le raisonnement par rapport aux programmes multi-thread puisque le programmeur n’a pas à se soucier de la sécurité du thread.
Ce modèle est généralement le meilleur choix lorsqu’il y a de nombreuses tâches indépendantes et n’ayant pas besoin de communiquer ou de s’attendre, ou lorsque certaines de ces tâches bloquent en attendant sur des événements.
Il s’agit aussi d’un bon choix quand une application doit partager des données mutables entre les tâches, puisqu’aucune synchronisation n’a besoin d’être effectuée. Les applications de mise en réseau ont très souvent ces propriétés, ce qui les rend particulièrement adaptées à la programmation event-driven.
En résumé, Twisted offre le parallélisme de la programmation multithread combinée avec la facilité de raisonnement de la programmation mono-thread
Qu'est-ce que le réacteur de Twisted ?
Le concept de réacteur ou reactor consiste à répartir les événements depuis de multiples sources vers leurs destinataires au sein d’un environnement mono-thread. La boucle d’événement du réacteur est au coeur du fonctionnement de Twisted.
Le réacteur connaît le réseau, le système fichier et les événements de minuterie. Il attend les événements puis les prend en charge, permettant l’abstraction de comportement spécifique à la plateforme et présentant les interfaces pour simplifier la réponse aux événements n’importe où sur le stack réseau.
Un réacteur basé sur l‘API poll est proposé par défaut sur toutes les plateformes. D’autres APIs de multiplexage à haut volume spécifique à certaines plateformes sont également pris en charge.
On peut citer pour exemple le réacteur KQueue basé sur le mécanisme kqueue de FreeBSD, le réacteur basé sur l’interface epoll, ou encore un réacteur IOCP basé sur les ports de complétion I/O de Windows.
En guise d’exemples de détails dépendants de l’interrogation de l’implémentation pris en charge par Twisted, on peut citer les limites de réseau et de système fichier, le comportement de mise en mémoire tampon, la méthode de détection d’une connexion perdue, ou les valeurs retournées en cas d’erreur.
L’implémentation du réacteur de Twisted prend aussi en charge l’utilisation des APIs non-blocantes sous-jacentes. Le langage Python n’expose pas l’API IOCP, et Twisted maintient donc sa propre implémentation.
Comment effectuer des test avec Twisted ?
Twisted propose une suite de test complète pouvant être exécutée avec la commande « tox ». Par exemple, tox – 1 permet de voir tous les environnements de test, tox -e nocov exécute tous les tests sans couvertures, tox -e withcov lance les tests avec couverture, et tox -e alldeps-withcov-posix installe toutes les dépendances et exécute les tests avec couverture sur la plateforme POSIX.
Il est possible d’exécuter la suite de tests sur les différents réacteurs avec la variable d’environnement TWISTED_REACTOR :« $ env TWISTED_REACTOR=epoll tox -e alldeps-withcov-posix ».
Certains de ces tests peuvent échouer si les dépendances requises pour un sous-système spécifique ne sont pas installées, si un firewall bloque certains prots, ou s’ils sont exécutés en tant que root.
En outre, il est possible de vérifier que le code soit conforme aux standards de Twisted. La commande « tox -e lint » permet d’exécuter pre-commit, et la commadne « tox -e mypy » exécute le vérificateur MyPy pour détecter les erreurs de frappe dans le code statique.
Comment installer Twisted ?
Avant de commencer à développer des applications avec Twisted, il est nécessaire de le télécharger et de l’installer avec toutes ses dépendances.
Pour une installation sur Linux, tapez la commande « apt-get install python-twisted » sur un système basé dpkg ou « yum install python-twisted » sur un système basé rpm.
Pour une installation sur Windows, vous trouverez les installateurs MSI et EXE en 32-bit et 64-bit. Si vous n’être pas sûr de la version dont vous avez besoin, le MSI 32-bit fonctionne toujours. Téléchargez et lancer l’installateur Twisted et l’installateur zope.interface depuis la page d’accueil.
Il est également possible d’installer des packages et dépendances optionnelles pour profiter de fonctionnalités supplémentaires de Twisted. Un PPA Ubuntu est disponible sur la page Launchpad de l’équipe Twisted-dev, avec des packages pour la dernière version Twisted sur toutes les versions actives d’Ubuntu. Pour les fonctionnalités SSL ou SSH, les packages pyOpenSSL et PyCrypto sont disponibles en tant que python-openssl et python-crypto.
La communauté de Twisted
Si vous avez besoin de conseil pour un projet, vous pouvez demander de l’aide à la communauté Twisted. Les contributeurs sont toujours prêts à apporter leur soutien.
Il existe deux listes de mailing principales. La liste twisted-python est une liste de discussion générale pour les questions liées au développement, et sert aussi aux annonces liées à Twisted et aux projets l’utilisant.
Cette liste est aussi utilisée pour organiser des sprints, discuter de tickets, demander des retours sur leurs projets, et discuter de la maintenance et l’infrastructure du projet. La liste twisted-web est dédiée aux discussions sur les technologies web liées à Twisted.
Des canaux IRC #twisted et #twisted.web sont également accessibles via le réseau Freenode. Ces canaux sont très actifs, mais il est possible d’envoyer un message à la liste appropriée si vous ne recevez pas de réponse imédiate.
On retrouve aussi de nombreuses questions et réponses liées à Twisted sur Stack Overflow, et les développeurs publient des rapports de sprint et des annonces de relaxe sur le blog officiel. Les blogs personnels des développeurs sont agrégés sur Planet Twisted.
Conclusion
Twisted est longtemps resté une référence pour la création de serveurs ou d’applications internet en Python. Toutefois, cet outil open source peine à s’adapter aux évolutions d’internet et de son usage. Néanmoins, les nombreuses extensions en font un outil flexible et extensible.
Afin d’apprendre à maîtriser Twisted et le langage Python, vous pouvez choisir DataScientest. Toutes nos formations comportent un module dédié à ce langage de programmation.
Nos différents cursus permettent d’acquérir les compétences requises pour exercer les professions de Data Analyst, Data Scientist, Data Engineer, Machine Learning Engineer ou Data Product Manager.
Nos programmes se complètent intégralement à distance via le web, et notre organisme reconnu par l’État est éligible au Compte Personnel de Formation. Découvrez DataScientest !
Vous savez tout sur Twisted. Pour plus d’informations sur ce sujet, découvrez notre dossier complet sur Python et notre dossier sur IPython.