Twisted contient un un grand nombre d'exemples . L'un d'entre eux en particulier, le "tutoriel "évolution du doigt contient une explication détaillée de la manière dont un programme asynchrone se développe à partir d'un tout petit noyau jusqu'à un système complexe comportant de nombreuses pièces mobiles. Un autre tutoriel qui pourrait vous intéresser est celui qui traite simplement de serveurs d'écriture .
La chose essentielle à garder à l'esprit concernant Twisted, ou même d'autres bibliothèques de mise en réseau asynchrone (telles que asynchrone , MINA ou ACE ), c'est que votre code n'est invoqué que lorsque quelque chose se produit. La partie que j'ai entendue le plus souvent ressembler à du "voodoo" est la gestion des callbacks : par exemple, Deferred
. Si vous avez l'habitude d'écrire du code qui s'exécute en ligne droite et n'appelle que des fonctions qui renvoient immédiatement des résultats, l'idée d'attendre que quelque chose vous rappelle peut être déroutante. Mais il n'y a rien de magique, ni de "vaudou" dans les rappels. Au niveau le plus bas, le réacteur se contente de rester assis et d'attendre qu'un petit nombre de choses se produisent :
- Les données arrivent sur une connexion (elles appellent
dataReceived
sur un protocole)
- Le temps s'est écoulé (il appellera une fonction enregistrée auprès de
callLater
).
- Une connexion a été acceptée (elle appelle
buildProtocol
sur une usine enregistrée avec un listenXXX
o connectXXX
fonction).
- Une connexion a été interrompue (il appellera
connectionLost
sur le protocole approprié)
Tout programme asynchrone commence par brancher quelques-uns de ces événements, puis lance le réacteur pour attendre qu'ils se produisent. Bien entendu, les événements qui se produisent entraînent d'autres événements qui sont connectés ou déconnectés, et votre programme poursuit ainsi son chemin. Au-delà de cela, la structure des programmes asynchrones n'a rien d'intéressant ou de spécial ; les gestionnaires d'événements et les callbacks sont simplement des objets, et votre code s'exécute de la manière habituelle.
Voici un simple "moteur piloté par les événements" qui vous montre à quel point ce processus est simple.
# Engine
import time
class SimplestReactor(object):
def __init__(self):
self.events = []
self.stopped = False
def do(self, something):
self.events.append(something)
def run(self):
while not self.stopped:
time.sleep(0.1)
if self.events:
thisTurn = self.events.pop(0)
thisTurn()
def stop(self):
self.stopped = True
reactor = SimplestReactor()
# Application
def thing1():
print 'Doing thing 1'
reactor.do(thing2)
reactor.do(thing3)
def thing2():
print 'Doing thing 2'
def thing3():
print 'Doing thing 3: and stopping'
reactor.stop()
reactor.do(thing1)
print 'Running'
reactor.run()
print 'Done!'
Au cœur des bibliothèques comme Twisted, la fonction dans la boucle principale n'est pas sleep
mais un appel du système d'exploitation comme select()
o poll()
tel qu'exposé par un module comme le module Python select . Je dis "comme" select
car il s'agit d'une API qui varie beaucoup d'une plate-forme à l'autre, et presque chaque boîte à outils d'interface graphique possède sa propre version. Twisted fournit actuellement une interface abstraite pour 14 variations différentes sur ce thème. La chose commune qu'une telle API fournit est un moyen de dire "Voici une liste d'événements que j'attends. Endors-toi jusqu'à ce que l'un d'eux se produise, puis réveille-toi et dis-moi lequel c'était".
5 votes
J'espère que vous avez plus de chance avec le twist. C'est actuellement l'un de mes frameworks préférés.