Ответ 1
Twisted содержит большое количество примеров. В частности, в "эволюция Finger" учебника содержится подробное объяснение того, как асинхронная программа растет с очень маленького ядра до сложного система с множеством движущихся частей. Другой, который может вас заинтересовать, - это руководство по простому написанию серверов.
Главное, чтобы иметь в виду Twisted или даже другие асинхронные сетевые библиотеки (такие как asyncore, MINA, или ACE) заключается в том, что ваш код активируется когда что-то происходит. Часть, которую я слышал чаще всего, звучит как "voodoo" - это управление обратными вызовами: например, Deferred
. Если вы привыкли писать код, который работает по прямой, и только вызывает функции, которые немедленно возвращаются с результатами, идея ждать чего-то, чтобы перезвонить вам может быть запутанной. Но нет ничего волшебного, никакого "вуду" о обратных вызовах. На самом низком уровне реактор просто сидит и ждет одного из нескольких событий:
- Данные поступают на соединение (он будет вызывать
dataReceived
в протоколе) - Прошло время (он вызовет функцию, зарегистрированную в
callLater
). - Было принято соединение (он вызовет
buildProtocol
на factory, зарегистрированном с помощью функции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, - это способ сказать: "Вот список событий, которые я жду. Идите спать, пока не произойдет одно из них, затем проснитесь и скажите мне, какой из них он был."