Twisted содержит большое количество примеров . В частности, учебник «Эволюция пальца» содержит подробное объяснение того, как асинхронная программа превращается из очень маленького ядра в сложную систему с множеством движущихся частей. Еще один, который может вас заинтересовать, - это учебник о серверах записи .
Главное, что нужно иметь в виду, касательно Twisted или даже других асинхронных сетевых библиотек (таких как asyncore , MINA или ACE ), заключается в том, что Ваш код вызывается только тогда, когда что-то происходит. Часть, которую я слышал чаще всего, звучит как «вуду» - это управление обратными вызовами: например, Deferred
. Если вы привыкли писать код, который выполняется по прямой линии и вызывает только те функции, которые сразу же возвращают результаты, идея ожидания того, что вам что-нибудь перезвонят, может сбить вас с толку. Но в колбэках нет ничего волшебного, никакого "вуду". На самом низком уровне реактор просто сидит и ждет, когда произойдет одно из небольшого числа событий:
- Данные поступают по соединению (он будет вызывать
dataReceived
по протоколу)
- Время прошло (будет вызываться функция, зарегистрированная с
callLater
).
- Соединение было принято (оно вызовет
buildProtocol
на заводе, зарегистрированном с помощью функции listenXXX
или connectXXX
).
- Соединение было разорвано (вызовет
connectionLost
по соответствующему протоколу)
Каждая асинхронная программа начинается с подключения нескольких из этих событий, а затем запускает реактор, чтобы дождаться их возникновения. Конечно, происходящие события приводят к большему количеству событий, которые подключаются или отключаются, и поэтому ваша программа идет своим чередом. Кроме того, в асинхронной структуре программы нет ничего особенного, интересного или особенного; обработчики событий и обратные вызовы - это просто объекты, и ваш код выполняется обычным способом.
Вот простой «движок, управляемый событиями», который показывает, насколько прост этот процесс.
# 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!'
В ядре таких библиотек, как Twisted, функция в главном цикле - это не sleep
, а вызов операционной системы, такой как select()
или poll()
, представленный таким модулем, как модуль выбора Python. . Я говорю «нравится» select
, потому что это API, который сильно различается между платформами, и почти каждый инструментарий GUI имеет свою версию. В настоящее время Twisted предоставляет абстрактный интерфейс для 14 различных вариантов этой темы. Обычная вещь, которую предоставляет такой API - это предоставить способ сказать: «Вот список событий, которые я жду. Идите спать, пока не произойдет одно из них, затем проснитесь и скажите мне, какое из них это было. «