Search     or:     and:
 LINUX 
 Language 
 Kernel 
 Package 
 Book 
 Test 
 OS 
 Forum 
 iakovlev.org 
 Languages
 С
 GNU С Library 
 Qt 
 STL 
 Threads 
 C++ 
 Samples 
 stanford.edu 
 ANSI C
 Libs
 LD
 Socket
 Pusher
 Pipes
 Encryption
 Plugin
 Inter-Process
 Errors
 Deep C Secrets
 C + UNIX
 Linked Lists / Trees
 Asm
 Perl
 Python
 Shell
 Erlang
 Go
 Rust
 Алгоритмы
NEWS
Последние статьи :
  Тренажёр 16.01   
  Эльбрус 05.12   
  Алгоритмы 12.04   
  Rust 07.11   
  Go 25.12   
  EXT4 10.11   
  FS benchmark 15.09   
  Сетунь 23.07   
  Trees 25.06   
  Apache 03.02   
 
TOP 20
 Linux Kernel 2.6...3653 
 Trees...489 
 Clickhouse...460 
 Go Web ...455 
 Ethreal 4...452 
 Максвелл 3...420 
 Ext4 FS...411 
 C++ Patterns 3...402 
 Rodriguez 6...397 
 William Gropp...390 
 Ethreal 1...385 
 Secure Programming for Li...382 
 Steve Pate 1...381 
 Gary V.Vaughan-> Libtool...380 
 Ethreal 3...371 
 Assembler...360 
 DevFS...359 
 Стивенс 9...353 
 Ulrich Drepper...348 
 Стивенс 10...323 
 
  01.01.2024 : 3621733 посещений 

iakovlev.org

Асинхронное программирование на Twisted

Этот документ - для новичков в твистед , но уже знакомых с питоном , а также концептуально - с серверами , клиентами , сокетами. Будет дан обзор параллельному программированию - concurrent programming : non-blocking код или asynchronous код.

Введение в concurrent programming

Многие задачи требуют много времени на вычисления :

  1. Большая сложность вычислений - напр. факториалы для больших чисел
  2. Ожидание данных для получения результата.

Ожидание ответа

Одной из главных особенностей сетевого программирования является ожидание данных. Пусть у нас есть функция , которая отсылает e-mail. Этой функции нужно приконнектиться к удаленному серверу, дождаться реплики от него, проверить его , послать емайл, дождаться подтверждения, и отсоединиться.

Каждый из этих шагов занимает время. На программу сразу накладываются ограничения: она не может послать много писем одновременно, она вообще не может делать ничего , пока письмо отсылается.

В сетевом программировании возможно выполнять сразу несколько задач независимо от того , пришло ли время для них.

Не-ожидание данных

Один из алгоритмов:

  1. для каждого коннекта выделяется отдельный процесс.
  2. для каждого коннекта выделяется отдельный поток
  3. использовать не-блокирующий системный вызов для каждого коннекта

Не-блокирующий вызов

В Twisted используется третья модель: non-blocking calls.

Когда есть много коннектов , и с ними работает приложение , а не операционная система, то обычно используется функция, которая проверяет каждый коннект, готов ли он на чтение или на запись - в этом случае говорят об асинхронном - asynchronous, event-driven или callback-based - программировании.

В этом случае , наш пример с отсылкой емайла будет работать так:

  1. вызывается функция коннекта к удаленному серверу
  2. эта функция вернется сразу, а сообщение о том , что емайл отослан, будет послано после коннекта
  3. когда произойдет коннект , будет послано сообщение

Преимущество этой схемы в том, что пока емайл будет отправляться, остальная часть программы будет продолжать делать свою работу, т.е. открывать коннекты для других емайлов. Т.е. программа не будет висеть в ожидании коннекта.

Callbacks

В сетевом приложении есть специальный тип сообщения о том, что данные готовы - это т.н. callback. Приложение вызывает обычную функцию, а у этой функции одним из аргументов будет другая - коллбэк-функция - которая будет вызвана в нужный момент. callback function - отложенная функция , возвращающая данные.

В обычном - синхронном программировании - функция запрашивает данные, ждет их, и идет дальше. В асинхронном программировании, функция запрашивает данные, и если их нет, позволяет библиотеке сделать вызов callback function , когда эти данные прийдут.

Deferreds

Twisted использует т.н. Deferred обьект для управления последовательности callback. Клиентское приложение привязывает серию функций к deferred, которые будут вызваны в порядке получения асинхронных запросов - эти функции называются callbacks, или callback chain, а также другую группу функций, вызываемых в случае ошибок - errbacks или errback chain. Сначала вызывается первый callback, когда данные приходят, затем обьект Deferred начинает рулить очередью этих калл-бэков.

Проблемы, решаемые Deferreds

Вторая проблема, решаемая при параллельном программировании - при вычислении задач может возникнуть задержка,связанная с их интенсивностью. Занятый диск, перегруженная база данных, сетевой трафик относится также к этому классу.

Deferreds работает так, что позволяет Twisted-программам работать, а не висеть, независимо от того, пришли данные или нет. Это реализовано с помощью интерфейса callbacks. Библиотеки всегда в нужный момент сделают вызов либо Deferred.callback либо Deferred.errback. Приложения будут обрабатывать callbacks и errbacks в порядке их вызова.

Базовая идея Deferreds в том, чтобы CPU был максимально освобожден от рутины ожидания.

В Twisted, сигнал для вызова ожидающей callback-функции возвращается Deferred. После этого вызывается нужный callbacks .

Deferreds - сигнал о том , что данные еще не готовы

В нашем примере с емайл, родительская функция вызывает функцию коннекта к удаленному серверу. Эта функция коннекта должна вернуться немедленно. Как родительская функция узнает, что коннекта до сих пор нет?

В Twisted есть обьект, который просигнализирует об этом. Когда коннект-функция вернет управление, этот обьект просигнализирует, что коннект не сделан. Называется он twisted.internet.defer.Deferred object.

Deferred имеет 2 цели. Первая говорит о том, что этот обьект - сигнал о том, что результат до сих пор не достигнут. Вторая - обьект можно запросить, когда данные будут получены.

Callbacks

Запросить у Deferred сами данные - сделать в Deferred вызов функции по приходу данных.

Одна из функций , возвращаемая Deferred - twisted.web.client.getPage. В этом примере мы делаем вызов getPage, когда возвращается Deferred, и привязываем callback, чтобы прочитать контент страницы по приходу данных:

 from twisted.web.client import getPage
 
 from twisted.internet import reactor
 
 def printContents(contents):
     '''
     This is the 'callback' function, added to the Deferred and called by
     it when the promised data is available
     '''
 
     print "The Deferred has called printContents with the following contents:"
     print contents
 
     # Stop the Twisted event handling system -- this is usually handled
     # in higher level ways
     reactor.stop()
 
 # call getPage, which returns immediately with a Deferred, promising to
 # pass the page contents onto our callbacks when the contents are available
 deferred = getPage('http://iakovlev.org/')
 
 # add a callback to the deferred -- request that it run printContents when
 # the page content has been downloaded
 deferred.addCallback(printContents)
 
 # Begin the Twisted event handling system to manage the process -- again this
 # isn't the usual way to do this
 reactor.run()
 

Как применить Deferreds сразу для 2-х callbacks,при этом результат первого передать во второй: :

from twisted.web.client import getPage
 
 from twisted.internet import reactor
 
 def lowerCaseContents(contents):
     '''
     This is a 'callback' function, added to the Deferred and called by
     it when the promised data is available. It converts all the data to
     lower case
     '''
 
     return contents.lower()
 
 def printContents(contents):
     '''
     This a 'callback' function, added to the Deferred after lowerCaseContents
     and called by it with the results of lowerCaseContents
     '''
 
     print contents
     reactor.stop()
 
 deferred = getPage('http://iakovlev.org/')
 
 # add two callbacks to the deferred -- request that it run lowerCaseContents
 # when the page content has been downloaded, and then run printContents with
 # the result of lowerCaseContents
 deferred.addCallback(lowerCaseContents)
 deferred.addCallback(printContents)
 
 reactor.run()
 

Error handling: errbacks

Callback может вернуть как данные , так и ошибку: дисконнект, ошибочные данные, ошибку протокола и т.д. Можно добавить в Deferred error handlers ('errbacks'), который будет срабатывать, когда произойдет ошибка :

from twisted.web.client import getPage
 
 from twisted.internet import reactor
 
 def errorHandler(error):
     '''
     This is an 'errback' function, added to the Deferred which will call
     it in the event of an error
     '''
 
     # this isn't a very effective handling of the error, we just print it out:
     print "An error has occurred: <%s>" % str(error)
     # and then we stop the entire process:
     reactor.stop()
 
 def printContents(contents):
     '''
     This a 'callback' function, added to the Deferred and called by it with
     the page content
     '''
 
     print contents
     reactor.stop()
 
 # We request a page which doesn't exist in order to demonstrate the
 # error chain
 deferred = getPage('http://twistedmatrix.com/does-not-exist')
 
 # add the callback to the Deferred to handle the page content
 deferred.addCallback(printContents)
 
 # add the errback to the Deferred to handle any errors
 deferred.addErrback(errorHandler)
 
 reactor.run()
 

Итоги

  1. для нетривиальных сетевых программ необходим параллелизм;
  2. Twisted framework поддерживает параллелизм в форме асинхронных вызовов;
  3. Twisted framework имеет обьект Deferred, управляющий callback-ми
  4. на примере функции getPage мы разобрали, как работает Deferred ;
  5. к Deferred можно приаттачить как callbacks, так и errbacks
Оставьте свой комментарий !

Ваше имя:
Комментарий:
Оба поля являются обязательными

 Автор  Комментарий к данной статье
igor
  super statia po twisted!!!
2011-06-25 15:46:31