Twisté contient un large number of examples. Un en particulier, le "evolution of Finger" tutorial, contient une explication détaillée de la façon dont un programme asynchrone se développe à partir d'un très petit noyau jusqu'à un système complexe avec beaucoup de parties mobiles. Un autre qui pourrait vous intéresser est le tutoriel sur simplement writing servers.
La chose à garder à l'esprit sur Twisted, ou même d'autres bibliothèques de réseaux asynchrones (tels que asyncore, MINA ou ACE), est que votre code est invoqué que lorsque quelque chose se passe. La partie que j'ai entendu le plus souvent ressembler à "vaudou" est la gestion des rappels: 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 retournent immédiatement avec 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, pas de "vaudou" à propos des rappels. Au niveau le plus bas, le réacteur est juste assis autour et attendre un d'un petit nombre de choses à se produire:
- arrive données sur une connexion (il appellera
dataReceived
sur un protocole)
- Le temps a passé (il appellera une fonction enregistrée avec
callLater
).
- Une connexion a été acceptée (elle appellera
buildProtocol
sur une usine enregistrée avec une fonction listenXXX
ou connectXXX
).
- Une connexion est tombé (il appellera
connectionLost
sur le protocole approprié)
Chaque programme asynchrone démarre en accrochant un peu de ces événements, puis le coup d'envoi du réacteur à attendre qu'ils se produisent. Bien sûr, les événements qui se produisent mènent à plus d'événements qui se connectent ou se déconnectent, et ainsi votre programme continue son bonhomme de chemin. Au-delà de cela, il n'y a rien de spécial au sujet de la structure de programme asynchrone qui soit intéressante ou spéciale; Les gestionnaires d'événements et les rappels ne sont que des objets, et votre code est exécuté 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 de bibliothèques comme Twisted, la fonction dans la boucle principale est non sleep
, mais un appel de système d'exploitation comme select()
ou poll()
, comme exposé par un module comme the Python select module. Je dis "comme" select
, parce que c'est une API qui varie beaucoup entre les plates-formes, et presque chaque boîte à outils GUI a sa propre version. Twisted fournit actuellement une interface abstraite à 14 variations différentes sur ce thème. La chose commune qu'une telle API fournit est de fournir une façon de dire: «Voici une liste d'événements que j'attends: Allez dormir jusqu'à ce que l'un d'eux se produise, puis réveillez-vous et dites-moi lequel."
J'espère que vous avez plus de chance avec twisted.Il est actuellement l'un de mes cadres préférés. – Dustin