Сравнение веб-серверов приложений на основе Python. Разработка для Web с помощью Django и Python

Программирование на Python

Часть 11. Web-программирование: Django

Серия контента:

Одной из наиболее фундаментальных архитектур для приложений является так называемая архитектура модель-представление-контроллер (Model-View-Controller) или MVC, которая разделяет базовый функционал приложения на ряд отдельных компонентов. При этом достигается главная цель: одна модель на много приложений.

Джанго – это высокоуровневый питоновский Web-фреймворк, который реализован на основе архитектуры MVC. Джанго имеет прозрачный дизайн, дает возможность для оперативной разработки Web-приложений, позволяет разрабатывать динамические Web-сайты.

Отличительные особенности джанго:

  • любой запрос обрабатывается программно и перенаправляется на свой адрес(url);
  • разделение контента и представления с помощью шаблонов;
  • абстрагирование от низкого уровня баз данных.

Джанго-приложение состоит из четырех основных компонентов.

  1. Модель данных: данные являются сердцевиной любого современного Web-приложения. Модель – важнейшая часть приложения, которое постоянно обращается к данным при любом запросе из любой сессии. Любая модель является стандартным питоновским классом. Объектно-ориентированный маппер (ORM) обеспечивает таким классам доступ непосредственно к базам данных. Если бы не было ORM, программисту пришлось бы писать запросы непосредственно на SQL. Модель обеспечивает облегченный механизм доступа к слою данных, инкапсулирует бизнес-логику. Модель не зависит от конкретного приложения. Данными можно манипулировать даже из командной строки, не используя при этом Web-сервер.
  2. Представление (view): вьюхи в джанге выполняют разнообразные функции, в том числе контролируют запросы пользователя, выдают контекст в зависимости от его роли. View – это обычная функция, которая вызывается в ответ на запрос какого-то адреса (url) и возвращает контекст.
  3. Шаблоны: они являются формой представления данных. Шаблоны имеют свой собственный простой метаязык и являются одним из основных средств вывода на экран.
  4. URL: это всего лишь механизм внешнего доступа к представлениям (view). Встроенные в урлы регулярные выражения делают механизм достаточно гибким. При этом одно представление может быть сконфигурировано к нескольким урлам, предоставляя доступ различным приложениям. Здесь поддерживается философия закладок: урлы становятся как бы самодостаточными и начинают жить независимо от представления.

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

Сегодня мы рассмотрим следующие темы.

  1. Как инсталлировать джанго.
  2. Первое приложение.
  3. Подключение базы данных.
  4. Первое представление.
  5. Шаблоны.
  6. Администрирование.

1. Как инсталлировать джанго

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

После разархивации в каталоге проекта запустите команду:

setup.py install > import django

Проверка версии джанго:

> django.VERSION

На данный момент официальная стабильная версия – 1.1.1.

2. Первое приложение

Для создания первого приложения зайдем в свой домашний каталог и запустим команду:

django-admin.py startproject mysite

Будет создан подкаталог mysite, где и будет лежать приложение. Заходим в созданный каталог и видим следующую файловую структуру:

mysite/ __init__.py manage.py settings.py urls.py

Init__.py – пустой файл, который подключает текущий каталог как стандартный питоновский пакет.

manage.py – утилита, управляющая сайтом.

settings.py – конфигурация сайта.

urls.py – таблица урлов или таблица для всего контента сайта.

Для того чтобы загрузить наше Web-приложение, запустим команду:

python manage.py runserver Validating models... 0 errors found. Django version 1.1, using settings "mysite.settings" Development server is running at http://127.0.0.1:8000/ Quit the server with CONTROL-C.

Если теперь в браузере открыть адрес http://127.0.0.1:8000/, то убедимся в том, что приложение запущено: появится стандартное приглашение.

3. Подключение базы данных

Джанго поддерживает следующие серверы баз данных: PostgreSQL, SQLite, MySQL, Microsoft SQL Server, Oracle.

В нашем примере мы выбираем постгрес – не потому, что он лучше, это не имеет принципиального значения. Убедитесь в том, что постгрес уже установлен на вашей системе, в противном случае его нужно проинсталлировать. После этого в файле settings.py пропишем настройки для постгреса:

DATABASE_ENGINE = "postgresql_psycopg2" DATABASE_NAME = "mysite" DATABASE_USER = "postgres" TIME_ZONE = "Europe/Moscow" LANGUAGE_CODE = "ru-ru"

Запускаем две команды, которые создают базу данных mysite – постгрес перед этим, естественно, должен быть уже запущен:

psql -d template1 -U postgres -c "DROP DATABASE mysite;" psql -d template1 -U postgres -c "CREATE DATABASE mysite WITH OWNER postgres ENCODING="UNICODE";"

Запускаем команду, которая создает в этой базе около 10 системных таблиц:

python manage.py syncdb

4. Первое представление

Теперь сгенерируем каркас для нашего Web-приложения:

python manage.py startapp People

Внутри каталога mysite появится подкаталог People со следующей структурой:

People/ __init__.py models.py tests.py views.py

Добавим в settings.py последнюю строку, которая добавляет новый путь:

INSTALLED_APPS = ("django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.sites", "mysite.People")

В settings.py в качестве корневого адреса должен быть:

ROOT_URLCONF = "mysite.urls"

Создадим модель Person – стандартный питоновский класс с двумя атрибутами – имя, и-мейл. Файл models.py:

from django.db import models class Person(models.Model): name = models.CharField("name", max_length=200) email = models.EmailField("Email", blank=True) def __str__(self): return "%s" % (self.name)

После того как добавляется новая модель, ее нужно синхронизировать с базой данных. Для этого из командной строки выполняем команду:

python manage.py syncdb

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

Теперь напишем простейшее представление, которое выведет приглашение-файл views.py:

from django.shortcuts import HttpResponse from mysite.People.models import Person def index(request): html = "

People !!!


" return HttpResponse(html)

Добавим урл – файл urls.py:

from django.conf.urls.defaults import * urlpatterns = patterns("", (r"^People/$", "mysite.People.views.index"))

Вновь запускаем Web-приложение:

python manage.py runserver

Открываем адрес в браузере и видим приглашение:

http://127.0.0.1:8000/People/

5. Шаблоны

В корне каталога mysite создадим каталог templates. В файле settings.py добавим строку:

TEMPLATE_DIRS = ("/home/mysite/templates")

Добавленный путь должен быть абсолютным. В добавленный каталог положим файл person.htnl следующего содержания:

People !!!


Personal Information
  • Name: {{p.name}}
  • Email: {{ p.email }}
  • В нашем единственном представлении index мы сделаем изменения: создадим объект Person и передадим его в вызываемый шаблон в качестве параметра. В шаблоне мы берем атрибуты этого параметра с помощью префикса двойных кавычек:

    {{p.name}} {{p.email}}

    Файл views.py после подключения шаблона теперь будет выглядеть так:

    from mysite.People.models import Person from django.shortcuts import render_to_response, get_object_or_404 def index(request): person = Person() person.name = "Alex" person.email = "[email protected]" return render_to_response("person.html", {"p": person})

    После перезагрузки Web-страницы в браузере мы увидим эти атрибуты.

    6. Администрирование

    Администраторская часть в джанго по умолчанию отключена. Для ее включения добавим последнюю строку в settings.py:

    INSTALLED_APPS = ("django.contrib.auth", "django.contrib.contenttypes", "django.contrib.sessions", "django.contrib.sites", "mysite.People", "django.contrib.admin")

    Для работы с админской частью нужно иметь рутовые права, поэтому нужно вначале создать суперпользователя:

    python manage.py createsuperuser

    После этого запустим команду:

    python manage.py syncdb

    Файл urls.py с добавленным админским функционалом будет иметь следующий вид:

    from django.conf.urls.defaults import * from django.contrib import admin admin.autodiscover() urlpatterns = patterns("", (r"^admin/", include(admin.site.urls)), (r"^People/$", "mysite.People.views.index"))

    Запускаем Web-приложение:

    python manage.py runserver

    Набираем в браузере адрес: http://127.0.0.1:8000/admin/. И попадаем на страницу логина. После ввода логина и пароля суперпользователя открывается админская часть. В ней можно добавлять и редактировать объекты.

    Заключение

    Итак, сегодня мы узнали, что такое Джанго и почему стоит остановить на нем свой выбор. Это бесплатный фреймворк, который поддерживает модель MVC, имеет несколько программных интерфейсов к различным базам данных, интуитивно понятный интерфейс администрирования с возможностью расширения, поддержку многоязычности и т.д. Этот Web-фреймворк обладает рядом преимуществ: джанго хорошо документирован – сайт разработчиков http://www.djangoproject.com/ тому подтверждение. Легкость установки и настройки помогают значительно экономить время. Малое число внешних зависимостей удобно для пользования: все, что нам нужно – это питон. На этом наш цикл статей можно считать завершенным. Конечно, автор не ставил перед собой задачи написать подробный учебник или справочник, скорее здесь речь идет о кратком вводном курсе для разработчиков, желающих освоить новый для себя инструмент.

    Код примеров проверялся на версии питона 2.6.

    Ресурсы для скачивания

    static.content.url=http://www.сайт/developerworks/js/artrating/

    Zone=Linux, Open source

    ArticleID=517107

    ArticleTitle=Программирование на Python: Часть 11. Web-программирование: Django

    В статье хотелось бы поднять вопросы отличия использования Python для web-разработки по сравнению с оной на PHP. Надеюсь, статья не приведет к холиварам, так как она вовсе не о том, какой язык лучше или хуже, а исключительно о технических особенностях Python.

    Немного о самих языках

    PHP - веб-ориентированный язык, создан, чтобы умирать (в хорошем смысле слова). С низкоуровневой точки зрения приложение на PHP представляет собой скорее набор отдельных скриптов возможно с единой семантической точкой входа.

    Python - универсальный язык программирования, применимый в том числе и в вебе. С технической точки зрения web-приложение на Python - полноценное приложение, загруженное в память, обладающее своим внутренним состоянием, сохраняемым от запроса к запросу.

    Исходя из вышеописанных особенностей вытекают и различия в обработке ошибок в web-приложениях. В PHP существует целый зоопарк типов ошибок (errors, exceptions), далеко не каждую из которых можно перехватить, хотя это (невозможность перехвата) и не имеет большого значения, так как приложение живет ровно столько, сколько обрабатывается один запрос. Неперехваченная ошибка просто приводит к досрочному выходу из обработчика, и удалению приложения из памяти. Новый запрос будет обрабатываться новым «чистым» приложением. В Python же приложение постоянно находится в памяти, обрабатывая множество запросов без «перезагрузки». Таким образом поддерживать правильное предсказуемое состояние приложения крайне важно. Все ошибки используют стандартный механизм исключений и могут быть перехвачены (разве что за исключением SyntaxError). Неперехваченная ошибка приведет к завершению приложения, которое понадобится перезапускать извне.

    Существует множество способов «приготовить» PHP и Python для веба. Далее я остановлюсь на двух наиболее мне знакомых (и кажется наиболее популярных) - PHP + FastCGI (php-fpm) и Python + WSGI (uWSGI). Конечно же, перед обоими этими связками предполагается наличие фронтенд-сервера (например, Nginx).

    Поддержка многопоточности Python

    Запуск сервера приложений (например, uWSGI) приводит к загрузке интерпретатора Python в память, а затем загрузке самого web-приложения. Обычно bootstrap-модуль приложения импортирует необходимые ему модули, производит вызовы инициализации и в итоге экспортирует подготовленный callable объект, соответствующий спецификации WSGI. Как известно, при первом импорте Python-модулей, код внутри них исполняется, в том числе создаются и инициализируются значениями переменные. Между двумя последовательными HTTP-запросами состояние интерпретатора не сбрасывается, следовательно сохраняются значения всех переменных уровня модуля.

    Напишем простейшее WSGI-приложение, которое наглядно продемонстрирует вышеописанное на примере:

    N = 0 def app(env, start_response): global n n += 1 response = "%.6d" % n start_response("200 OK", [("Content-Type", "text/plain")]) return
    Здесь n является переменной модуля и она будет создана со значением 0 при загрузке приложения в память следующей командой:

    Uwsgi --socket 127.0.0.1:8080 --protocol http --single-interpreter --processes 1 -w app:app
    Само приложение просто выводит на страницу значение переменной n . Для заядлых PHP программистов оно выглядит бессмысленным, так как «должно» каждый раз выводить на страницу строку «000001».

    Проведем тест:

    Ab -n 500 -c 50 http://127.0.0.1:8080/ curl http://127.0.0.1:8080
    В результате мы получим строку «000501» , что подтверждает наше утверждение, о том, что приложение находится загруженным в память uwsgi и сохраняет свое состояние между запросами.

    Если запустить uWSGI с параметром --processes 2 и провести тот же тест, то несколько последовательных вызовов curl покажут, что мы имеем уже 2 различные возрастающие последовательности. Так как ab посылает 500 запросов, примерно половина из них приходится на один процесс uWSGI, а остальные - на второй. Ожидаемые значения, возращаемые curl будут примерно «000220» и «000280» . Интерпретатор Python, судя по всему, один на процесс, и мы имеем 2 независимых окружения и реальную параллельную обработку запросов (в случае многоядерного процессора).

    Python поддерживает потоки, как часть языка. Классическая реализация (CPython) использует нативные потоки OS, но есть GIL - в один момент времени выполняется только один поток. При этом все равно возможны проблемы race condition, так как даже n += 1 не является атомарной операцией.

    Дизассемблируем python код

    «Дизассемблируем» наше WSGI-приложение:
    import dis n = 0 def app(env, start_response): global n n += 1 return if "__main__" == __name__: print(dis.dis(app))
    8 0 LOAD_GLOBAL 0 (n) 3 LOAD_CONST 1 (1) 6 INPLACE_ADD 7 STORE_GLOBAL 0 (n) 10 10 LOAD_GLOBAL 1 (bytes) 13 LOAD_GLOBAL 2 (str) 16 LOAD_GLOBAL 0 (n) 19 CALL_FUNCTION 1 (1 positional, 0 keyword pair) 22 LOAD_CONST 2 ("utf-8") 25 CALL_FUNCTION 2 (2 positional, 0 keyword pair) 28 BUILD_LIST 1 31 RETURN_VALUE
    Видно, что инкремент в нашей программе занимает 4 операции. Прерывание GIL может наступить на любой из них.


    Увеличение количества потоков при отсуствии ожидания IO в коде обработчиков HTTP-запросов не приводит к ускорению обработки (а скорее даже ее замедляет, так как потоки могут «толкаться», переключая контексты). Реальной параллельности потоки в следствие ограничеия GIL не создают, хоть и являются не green thread"ами, а настоящими потоками OS.

    Проведем еще один тест. Запустим uwsgi с 1 процессом, но 10 потоками-обработчиками в нем:

    Uwsgi --socket 127.0.0.1:8080 --protocol http --single-interpreter --processes 1 --threads 10 -w app:app
    и выполним с помощью ab 5000 запросов к приложению.

    Ab -n 5000 -c 50 http://127.0.0.1:8080/
    Последующие запросы curl 127.0.0.1 :8080 покажут, что мы имеем только одну возрастающую последовательность, значение которой <= 5000 (меньше 5000 оно может быть в случае race condition на инкременте).

    Влияние языка на архитектуру приложения

    Каждый HTTP-запрос обрабатывается в отдельном потоке (справедливо и для процессов, так как процесс имеет минимум 1 поток). При этом каждый поток за время своей жизни (которое в идеальных условиях совпадает со временем жизни всего uwsgi приложения) обрабатывает множество HTTP-запросов, сохраняя свое состояние (т.е. значения переменных уровня модулей) от запроса к запросу. В этом заключается чуть ли не основное отличие от модели обработки HTTP-запросов в PHP, где каждый запрос приходит новое только что проинициализированное окружение и загрузку приложения необходимо выполнять каждый раз заново.

    Типичным подходом в крупных web-приложениях на PHP является использование Dependency Injection Container для управления инициализацией и доступом к уровню сервисов приложения. Наглядным примером является Pimple . На каждый HTTP-запрос первым делом выполняется код инициализации, регистрирующий все доступные сервисы в контейнере. Далее по мере необходимости осуществляется доступ к объектом сервисов (lazy) в контроллерах. Каждый сервис может зависеть от других сервисов, зависимости разрешаются опять же через контейнер в коде инициализации сервиса-агрегата.

    // Определяем сервисы $container["session_storage"] = function ($c) { return new SessionStorage("SESSION_ID"); }; $container["session"] = function ($c) { return new Session($c["session_storage"]); }; // Используем сервисы class MyController { public function __construct() { // get the session object $this->session = $container["session"]; // "тестриуемость" страдает, но не суть } }
    Благодаря контейнеру, можно обеспечить единовременное создание объектов и возвращение уже готовых объектов на каждое последующее обращение к сервису (если необходимо). Но эта магия работает только в рамках одного HTTP-запроса, поэтому сервисы можно без проблем инициализировать специфичными для запроса значениями. Такие значения зачастую - это текущий авторизованный пользователь, сессия текущего пользователя, собственно HTTP-запрос и пр. В конце запроса сервисы все равно будут разрушены, а в начале обработки следующего запроса - созданы и проинициализированы новые. К тому же можно практически не беспокоиться об утечках памяти, если обработка одного HTTP-запроса умещается в отведенные для скрипта лимиты, так как создание сервисов происходит по требованию (lazy) и на один запрос каждый необходимый сервис скорее всего будет создан только в единственном экземпляре.

    Теперь, принимая во внимание вышеописанную поточную модель Python, можно заметить, что использование аналогичного подхода в Python web-приложении не возможно без дополнительных усилий. Если контейнер будет являться переменной уровня модуля (что выглядит вполне логично), все сервисы, которые он содержит, не могут быть проинициализированы специфичными для текущего запроса значениями, так как сервис будет являться разделяемым ресурсом между несколькими потоками, выполяющими обработку нескольких HTTP-запросов псевдо-параллельно. На первый взгляд существует два способа справиться с этой проблемой - сделать объекты сервисов независимыми от текущего HTTP-запроса (зависимыми остануться вызовы методов сервисов, а стековые переменные, используемые в методах, не являются разделяемыми ресурсами) или же сделать контейнер - ресурсом потока, а не процесса (тогда каждый поток будет общаться только со своим независимым набором сервисов, а в один момент времени один поток может обрабатывать только один HTTP-запрос).

    Кажущийся плюс первого подхода - сервисы инициализируются только один раз за все время жизни uwsgi процесса. Возможна также экономия памяти (так как имеем только один набор сервисов на все потоки). С другой стороны обработка конкретного HTTP-запроса требует лишь какого-то (скорее всего небольшого) поднможества всех доступных сервисов. Если же приложение достаточно большое и обладает внушительным количеством сервисов, то после обработки определенного числа HTTP-запросов, подавляющее большинство сервисов окажется проинициализировнными и находящимися в памяти процесса. Выглядит так, что это может оказаться серьезной проблемой.

    Второй подход можно реализовать с использованием

  • PHP ,
  • Python
  • Введение

    В статье хотелось бы поднять вопросы отличия использования Python для web-разработки по сравнению с оной на PHP. Надеюсь, статья не приведет к холиварам, так как она вовсе не о том, какой язык лучше или хуже, а исключительно о технических особенностях Python.

    Немного о самих языках

    PHP - веб-ориентированный язык, (в хорошем смысле слова). С низкоуровневой точки зрения приложение на PHP представляет собой скорее набор отдельных скриптов возможно с единой семантической точкой входа.

    Python - универсальный язык программирования, применимый в том числе и в вебе. С технической точки зрения web-приложение на Python - полноценное приложение, загруженное в память, обладающее своим внутренним состоянием, сохраняемым от запроса к запросу.

    Исходя из вышеописанных особенностей вытекают и различия в обработке ошибок в web-приложениях. В PHP существует целый зоопарк типов ошибок (errors, exceptions), далеко не каждую из которых можно перехватить, хотя это (невозможность перехвата) и не имеет большого значения, так как приложение живет ровно столько, сколько обрабатывается один запрос. Неперехваченная ошибка просто приводит к досрочному выходу из обработчика, и удалению приложения из памяти. Новый запрос будет обрабатываться новым «чистым» приложением. В Python же приложение постоянно находится в памяти, обрабатывая множество запросов без «перезагрузки». Таким образом поддерживать правильное предсказуемое состояние приложения крайне важно. Все ошибки используют стандартный механизм исключений и могут быть перехвачены (разве что за исключением SyntaxError). Неперехваченная ошибка приведет к завершению приложения, которое понадобится перезапускать извне.

    Существует множество способов «приготовить» PHP и Python для веба. Далее я остановлюсь на двух наиболее мне знакомых (и кажется наиболее популярных) - PHP + FastCGI (php-fpm) и Python + WSGI (uWSGI). Конечно же, перед обоими этими связками предполагается наличие фронтенд-сервера (например, Nginx).

    Поддержка многопоточности Python

    Запуск сервера приложений (например, uWSGI) приводит к загрузке интерпретатора Python в память, а затем загрузке самого web-приложения. Обычно bootstrap-модуль приложения импортирует необходимые ему модули, производит вызовы инициализации и в итоге экспортирует подготовленный callable объект, соответствующий спецификации WSGI. Как известно, при первом импорте Python-модулей, код внутри них исполняется, в том числе создаются и инициализируются значениями переменные. Между двумя последовательными HTTP-запросами состояние интерпретатора не сбрасывается, следовательно сохраняются значения всех переменных уровня модуля.

    Напишем простейшее WSGI-приложение, которое наглядно продемонстрирует вышеописанное на примере:

    N = 0 def app(env, start_response): global n n += 1 response = "%.6d" % n start_response("200 OK", [("Content-Type", "text/plain")]) return
    Здесь n является переменной модуля и она будет создана со значением 0 при загрузке приложения в память следующей командой:

    Uwsgi --socket 127.0.0.1:8080 --protocol http --single-interpreter --processes 1 -w app:app
    Само приложение просто выводит на страницу значение переменной n . Для заядлых PHP программистов оно выглядит бессмысленным, так как «должно» каждый раз выводить на страницу строку «000001».

    Проведем тест:

    Ab -n 500 -c 50 http://127.0.0.1:8080/ curl http://127.0.0.1:8080
    В результате мы получим строку «000501» , что подтверждает наше утверждение, о том, что приложение находится загруженным в память uwsgi и сохраняет свое состояние между запросами.

    Если запустить uWSGI с параметром --processes 2 и провести тот же тест, то несколько последовательных вызовов curl покажут, что мы имеем уже 2 различные возрастающие последовательности. Так как ab посылает 500 запросов, примерно половина из них приходится на один процесс uWSGI, а остальные - на второй. Ожидаемые значения, возращаемые curl будут примерно «000220» и «000280» . Интерпретатор Python, судя по всему, один на процесс, и мы имеем 2 независимых окружения и реальную параллельную обработку запросов (в случае многоядерного процессора).

    Python поддерживает потоки, как часть языка. Классическая реализация (CPython) использует нативные потоки OS, но есть GIL - в один момент времени выполняется только один поток. При этом все равно возможны проблемы race condition, так как даже n += 1 не является атомарной операцией.

    Дизассемблируем python код

    «Дизассемблируем» наше WSGI-приложение:
    import dis n = 0 def app(env, start_response): global n n += 1 return if "__main__" == __name__: print(dis.dis(app))
    8 0 LOAD_GLOBAL 0 (n) 3 LOAD_CONST 1 (1) 6 INPLACE_ADD 7 STORE_GLOBAL 0 (n) 10 10 LOAD_GLOBAL 1 (bytes) 13 LOAD_GLOBAL 2 (str) 16 LOAD_GLOBAL 0 (n) 19 CALL_FUNCTION 1 (1 positional, 0 keyword pair) 22 LOAD_CONST 2 ("utf-8") 25 CALL_FUNCTION 2 (2 positional, 0 keyword pair) 28 BUILD_LIST 1 31 RETURN_VALUE
    Видно, что инкремент в нашей программе занимает 4 операции. Прерывание GIL может наступить на любой из них.


    Увеличение количества потоков при отсуствии ожидания IO в коде обработчиков HTTP-запросов не приводит к ускорению обработки (а скорее даже ее замедляет, так как потоки могут «толкаться», переключая контексты). Реальной параллельности потоки в следствие ограничеия GIL не создают, хоть и являются не green thread"ами, а настоящими потоками OS.

    Проведем еще один тест. Запустим uwsgi с 1 процессом, но 10 потоками-обработчиками в нем:

    Uwsgi --socket 127.0.0.1:8080 --protocol http --single-interpreter --processes 1 --threads 10 -w app:app
    и выполним с помощью ab 5000 запросов к приложению.

    Ab -n 5000 -c 50 http://127.0.0.1:8080/
    Последующие запросы curl 127.0.0.1 :8080 покажут, что мы имеем только одну возрастающую последовательность, значение которой <= 5000 (меньше 5000 оно может быть в случае race condition на инкременте).

    Влияние языка на архитектуру приложения

    Каждый HTTP-запрос обрабатывается в отдельном потоке (справедливо и для процессов, так как процесс имеет минимум 1 поток). При этом каждый поток за время своей жизни (которое в идеальных условиях совпадает со временем жизни всего uwsgi приложения) обрабатывает множество HTTP-запросов, сохраняя свое состояние (т.е. значения переменных уровня модулей) от запроса к запросу. В этом заключается чуть ли не основное отличие от модели обработки HTTP-запросов в PHP, где каждый запрос приходит новое только что проинициализированное окружение и загрузку приложения необходимо выполнять каждый раз заново.

    Типичным подходом в крупных web-приложениях на PHP является использование Dependency Injection Container для управления инициализацией и доступом к уровню сервисов приложения. Наглядным примером является Pimple . На каждый HTTP-запрос первым делом выполняется код инициализации, регистрирующий все доступные сервисы в контейнере. Далее по мере необходимости осуществляется доступ к объектом сервисов (lazy) в контроллерах. Каждый сервис может зависеть от других сервисов, зависимости разрешаются опять же через контейнер в коде инициализации сервиса-агрегата.

    // Определяем сервисы $container["session_storage"] = function ($c) { return new SessionStorage("SESSION_ID"); }; $container["session"] = function ($c) { return new Session($c["session_storage"]); }; // Используем сервисы class MyController { public function __construct() { // get the session object $this->session = $container["session"]; // "тестриуемость" страдает, но не суть } }
    Благодаря контейнеру, можно обеспечить единовременное создание объектов и возвращение уже готовых объектов на каждое последующее обращение к сервису (если необходимо). Но эта магия работает только в рамках одного HTTP-запроса, поэтому сервисы можно без проблем инициализировать специфичными для запроса значениями. Такие значения зачастую - это текущий авторизованный пользователь, сессия текущего пользователя, собственно HTTP-запрос и пр. В конце запроса сервисы все равно будут разрушены, а в начале обработки следующего запроса - созданы и проинициализированы новые. К тому же можно практически не беспокоиться об утечках памяти, если обработка одного HTTP-запроса умещается в отведенные для скрипта лимиты, так как создание сервисов происходит по требованию (lazy) и на один запрос каждый необходимый сервис скорее всего будет создан только в единственном экземпляре.

    Теперь, принимая во внимание вышеописанную поточную модель Python, можно заметить, что использование аналогичного подхода в Python web-приложении не возможно без дополнительных усилий. Если контейнер будет являться переменной уровня модуля (что выглядит вполне логично), все сервисы, которые он содержит, не могут быть проинициализированы специфичными для текущего запроса значениями, так как сервис будет являться разделяемым ресурсом между несколькими потоками, выполяющими обработку нескольких HTTP-запросов псевдо-параллельно. На первый взгляд существует два способа справиться с этой проблемой - сделать объекты сервисов независимыми от текущего HTTP-запроса (зависимыми остануться вызовы методов сервисов, а стековые переменные, используемые в методах, не являются разделяемыми ресурсами) или же сделать контейнер - ресурсом потока, а не процесса (тогда каждый поток будет общаться только со своим независимым набором сервисов, а в один момент времени один поток может обрабатывать только один HTTP-запрос).

    Кажущийся плюс первого подхода - сервисы инициализируются только один раз за все время жизни uwsgi процесса. Возможна также экономия памяти (так как имеем только один набор сервисов на все потоки). С другой стороны обработка конкретного HTTP-запроса требует лишь какого-то (скорее всего небольшого) поднможества всех доступных сервисов. Если же приложение достаточно большое и обладает внушительным количеством сервисов, то после обработки определенного числа HTTP-запросов, подавляющее большинство сервисов окажется проинициализировнными и находящимися в памяти процесса. Выглядит так, что это может оказаться серьезной проблемой.

    Второй подход можно реализовать с использованием

    Dash - библиотека пользовательского интерфейса для создания аналитических веб-приложений. Она будет полезна для тех, кто использует Python для анализа и исследования данных, визуализации, моделирования и отчётности.

    Dash значительно упрощает создание GUI (графических пользовательских интерфейсов) для анализа данных. Вот пример приложения на Dash из 43 строк кода, который связывает выпадающее меню с графиком D3.js. Когда пользователь выбирает значение в выпадающем списке, код динамически экспортирует данные из Google Finance в Pandas DataFrame:

    Код Dash является декларативным и реактивным, что упрощает создание сложных приложений, содержащих множество интерактивных элементов. Вот пример с 5 входными данными, 3 - выходными и с перекрёстной фильтрацией. Это приложение было написано на Python, и в нём всего лишь 160 строк кода:

    Приложение на Dash с несколькими входными и выходными данным.

    Для каждого элемента приложения можно задать собственные параметры размера, расположения, цвета и шрифта. Приложения на Dash создаются и публикуются в Сети, поэтому к ним можно применить всё, на что способен CSS. Ниже иллюстрируется пример тонко настраиваемого интерактивного приложения отчётности на Dash, выполненного в стиле отчёта финансовой организации Goldman Sachs.

    Тонко настраиваемое приложение Dash, созданное в стиле отчёта финансовой организации Goldman Sachs.

    Вам не нужно писать какой-либо код на JavaScript или HTML, когда ваше приложение на Dash запущено в веб-браузере. Dash предоставляет богатый набор интерактивных веб-компонентов.

    Import dash_core_components as dcc dcc.Slider(value=4, min=-10, max=20, step=0.5, labels={-5: "-5 Degrees", 0: "0", 10: "10 Degrees"})

    Пример простого ползунка на Dash

    Dash предоставляет простой реактивный декоратор для привязки вашего кода анализа данных к пользовательскому интерфейсу Dash.

    @dash_app.callback(Output("graph-id", "figure"), ) def your_data_analysis_function(new_slider_value): new_figure = your_compute_figure_function(new_slider_value) return new_figure

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

    Ваша функция Python может выполнять различные действия с новым входным значением: может фильтровать объект DataFrame библиотеки Pandas, выполнять SQL-запрос, запускать симуляцию, выполнять вычисления или запускать тестирование. Dash рассчитывает, что ваша функция вернёт новое свойство для какого-нибудь элемента пользовательского интерфейса, будь то новый график, новая таблица или новый текст.

    В качестве примера ниже представлено приложение на Dash, которое обновляет текстовый элемент при взаимодействии с графиком. Код приложения фильтрует данные в Pandas DataFrame на основе выбранной точки:

    Приложение ниже отображает метаинформацию о лекарственных веществах при наведении курсора на точки в графике. Код приложения также добавляет строки в таблицу, когда появляются новые компоненты в выпадающем списке.

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

    Архитектура

    Flask и React.js

    Приложения на Dash - веб-серверы, которые запускают Flask и связывают пакеты JSON через HTTP-запросы. Интерфейс Dash формирует компоненты, используя React.js.

    Flask - великолепный фреймворк, который широко используется сообществом разработчиков Python во многих проектах. Основной экземпляр Flask и все его настраиваемые свойства доступны разработчикам приложений на Dash. Продвинутые разработчики могут расширить возможности приложений с помощью богатой коллекции плагинов Flask.

    React.js также великолепен, например, мы переписали всю нашу веб-платформу и наш онлайн-редактор диаграмм с помощью React. Но есть кое-что, что действительно радует насчёт React - активный и талантливый состав сообщества разработчиков, который опубликовал тысячи высококачественных компонентов, начиная с выпадающих списков и слайдеров , заканчивая календарями и . И всё это публикуется с открытым исходным кодом!

    Dash использует мощь Flask и React, подстраивая их под работу с Python для специалистов по анализу и обработке данных, которые могут не быть экспертами в области веб-разработки.

    От React.js к компонентам Python

    Компоненты Dash - это классы Python, которые кодируют свойства и значения конкретного компонента React и упорядочиваются как JSON. Dash предоставляет набор инструментов для лёгкой упаковки компонентов React в вид компонентов, которые могут быть использованы в Dash. Этот набор инструментов использует динамическое программирования для автоматического создания классов Python из аннотированного свойства React - propTypes . На выходе классы Python, которые представляют компоненты Dash, являются удобными для пользователя, так как они имеют автоматическую проверку аргументов, строк документации и прочее.

    Вот пример динамически сгенерированной проверки ошибочного аргумента:

    >>> import dash_core_components as dcc >>> dcc.Dropdown(valu=3) Ошибка: неизвестный ключевой аргумент `valu` Допустимые аргументы: id, className, disabled, multi, options, placeholder, value

    Пример динамически создаваемых строк документации:

    >>> help(dcc.Dropdown) class Dropdown(dash.development.base_component.Component) | Компонент выпадающего списка. | Компонент выпадающего списка служит для выбора одного или более | элементов. | значения и названия элементов выпадающего списка определяются в `options` | свойство и выбранный элемент(ы) определяются свойством `value`. | | используйте выпадающий список, только если у вас много вариантов выбора (больше 5), или | когда вы ограничены пространством. В противном случае вы можете использовать переключатели или чекбоксы, | Которые покажут сразу все элементы пользователю. | | Аргументы ключевых слов: | - id (строка; необязательный) | - className (строка; необязательный) | - disabled (логический тип; необязательный): если true, выбор блокируется | - multi (логический тип; необязательный): если true, пользователь может выбрать несколько значений | - options (список; необязательный) | - placeholder (строка; необязательный): серый текст по умолчанию, если ничего не выбрано | - value (строка | список; необязательный): значение поля ввода. Если `multi` false (по умолчанию), | то value - строка, соответствующая своим значениям, | указанным в свойстве `options`. Если `multi` - true, то | можно выбрать сразу несколько значений, а `value` - | массив элементов со значениями, соответствующими в свойстве | `options`. | | Доступные события: "change

    Полный набор HTML-тегов (наподобие div , img , table) также обрабатывается с помощью React, а их классы Python доступны через библиотеку dash_html_component . Основной набор интерактивных компонентов, таких как Dropdown , Graph , Slider , будет поддерживаться командой Dash через dash_core_components . Обе библиотеки используют стандартный набор инструментальных средств React-to-Dash с открытым исходным кодом, который вы могли бы использовать при необходимости написания своей собственной библиотеки компонентов.

    Ваше приложение автоматически не привязывается к библиотеке компонентов Dash. Библиотека компонентов импортируется отдельно от основной библиотеки Dash. С помощью набора инструментальных средств React-to-Dash можно легко записать или перенести компонент React.js в класс Python, который можно использовать в приложении Dash. На официальном сайте вы найдёте руководство по созданию собственных компонентов или можете попросить команду разработчиков Dash написать их для вас.

    Многопользовательские приложения

    Свойства приложения на Dash хранятся в интерфейсе (в браузере). Это позволяет использовать приложения, написанные с использованием Dash, в многопользовательском режиме: может быть открыто несколько независимых друг от друга сессий, в которых действия одних пользователей не будут влиять на данные других пользователей. Код приложения на Dash является функциональным: он может считывать значения из глобальных свойств Python, но не может вносить в них изменения. Этот функциональный подход можно легко обосновать и протестировать - это просто входные и выходные данные без каких-либо побочных эффектов или свойств.

    CSS и стили

    CSS и стили по умолчанию хранятся вне базовой библиотеки, чтобы сохранить принцип модульности и независимого управления версиями и чтобы подтолкнуть разработчиков Dash-приложений настраивать вид своих приложений. Команда Dash разместила руководство по основным стилям.

    Визуализация данных

    Библиотека Dash поставляется с компонентом Graph, который отвечает за отображение диаграмм с помощью Plotly.js. Библиотека Plotly.js отлично подходит к Dash (отличное дополнение), так как она декларативна и имеет открытый исходный код. Кроме того, она поддерживает полный спектр научных, финансовых и деловых диаграмм. Она создана на основе D3.js (для диаграмм типографического качества и экспорта векторных изображений) и WebGL (для высокопроизводительной визуализации).

    В библиотеке Dash элемент Graph использует тот же синтаксис, что и библиотека Plotly.py с открытым исходным кодом, что даёт вам возможность легко переключаться между ними. Компонент Graph подключается к системе событий Plotly.js, позволяя авторам писать приложения, которые реагируют на наведение курсора, щелчки и выбор определённых точек на графиках Plotly.

    Репозитории с открытым исходным кодом

    • документация и руководство по Dash;
    • Plotly.js  -JavaScript- библиотека, используемая Dash.

    Прототипирование

    Dash - это новая библиотека в среде Python, однако концепции и идеи, на которых строится Dash, существуют в течение десятилетий на разных языках и в разных приложениях.

    Если вы разбираетесь в Excel, значит, вам будет проще разобраться и в Dash. Ведь они оба используют «реактивную» модель программирования. В Excel ячейки с выходными данными обновляются автоматически при изменении параметров ячеек с входными данными. Любая ячейка может быть входной или выходной или и тем, и другим. В ячейках с входными данными нет информации о том, какие ячейки с выходными данными зависят от них, что упрощает добавление новых ячеек с выходными данными или позволяет связать несколько ячеек. Вот пример Excel-приложения:

    Можно провести аналогию для Dash. Вместо ячеек у нас есть богатый спектр веб-компонентов, таких как ползунки, поля ввода, выпадающие списки и графики. Вместо написания сценария Excel или VBA мы пишем код Python. Ниже представлено то же самое приложение, но в этот раз оно написано на Dash:

    App.layout = html.Div([ html.Label("Hours per Day"), dcc.Slider(id="hours", value=5, min=0, max=24, step=1), html.Label("Rate"), dcc.Input(id="rate", value=2, type="number"), html.Label("Amount per Day"), html.Div(id="amount"), html.Label("Amount per Week"), html.Div(id="amount-per-week") ]) @app.callback(Output("amount", "children"), ) def compute_amount(hours, rate): return float(hours) * float(rate) @app.callback(Output("amount-per-week", "children"), ) def compute_amount(amount): return float(amount) * 7

    Некоторым разработчикам нравится этот пример, потому что Excel по-прежнему занимает доминирующее положение даже в технических вычислениях и в финансовой математике. Я не думаю, что доминирующее положение Excel - это технический вопрос. В конце концов, есть легионы программистов, которые изучили нюансы Excel, VBA и даже SQL.

    Более того, таблицы Excel легче распространять, чем программы на Python, а ячейки Excel легче редактировать, чем аргументы командной строки.

    Тем не менее, моделирование в Excel имеет известные ограничения: эти таблицы часто становятся слишком большими или уязвимыми, чтобы переводить их на производственный уровень, проводить экспертную оценку или тестировать и поддерживать. Вам ведь знаком случай со знаменитой опечаткой в 2013 году?

    Надеемся, что Dash сделает использование Python в проектах по обработке данных проще. Благодаря одним и тем же функциональным и реактивным принципам, можно так же легко написать приложение на Dash, как написать аналитическую таблицу. Это, безусловно, более мощный и презентабельный инструмент.

    Фреймворк Shiny

    Если вы программируете на R, вам повезло. Shiny - это реактивный фреймворк для создания веб-приложений на чистом R, и это отлично! Вы даже можете создавать интерактивные графики с библиотекой Shiny или Plotly для R . Dash и Shiny похожи, но Dash не стремится быть копией Shiny, так как философии Python и R достаточно различаются, что приводит к необходимости использования разного синтаксиса.

    Интерактивное веб-приложение, созданное с помощью Shiny на языке R.

    Структурирование данных с MATLAB

    Если вы программируете на MATLAB, то вам, возможно, знакома GUIDE - библиотека пользовательского интерфейса для MATLAB. Компания Mathworks была одной из новаторов в области технических вычислений. GUIDE была написана в далёком 2004 году.

    Приложение, созданное с помощью библиотеки GUIDE на MATLAB.

    Если ваши данные структурированы в базе данных, вы могли бы использовать Tableau или любой другой BI-инструмент. Tableau - восхитительный инструмент. Компания установила новый вектор развития в своей отрасли, согласно которому, у конечного пользователя должна быть автономия, чтобы он мог иметь возможность исследовать данные внутри своей организации. Компания также помогла сделать популярнее концепции детализации данных и перекрёстной фильтрации.

    Перекрёстная фильтрация в Tableau.

    Dash также служит дополнением к BI-инструментам, наподобие вышеупомянутых. Они отлично подходят для структурирования данных. Но когда дело доходит до преобразования данных и аналитики, превзойти размах и гибкость языков программирования и сообществ, вроде Python, становится труднее. Dash абстрагируется от множества сложностей в создании пользовательских интерфейсов, позволяя вам сделать это красиво для вашей аналитической базы данных.

    Виджеты Jupyter

    Наконец, пришло время рассказать о виджетах Jupyter. Они обеспечивают действительно приятный фреймворк внутри интерфейса Notebook. Вы можете добавлять ползунки к вашим графикам в Jupyter Notebook.

    Виджеты в Dash похожи на виджеты Jupyter. В Jupyter Notebooks есть возможность добавлять виджеты непосредственно рядом с кодом. В Dash элементы управления хранятся отдельно от вашего кода. Dash больше нацелена на приложения для распространения, чем на распространяемый код и документацию. Вы всегда можете смешивать и сопоставлять инструменты, создавая свои приложения на Dash в среде Jupyter Notebook.

    Команде разработчиков Dash также очень нравится проект nteract , который действительно снижает порог вхождения в Python и Jupyter Notebook, позволяя упаковать Jupyter Notebook в виде настольного приложения.

    Лицензирование и бизнес-модель с открытым исходным кодом

    Стартап поддерживает библиотеки с открытым исходным кодом для Python, R и MATLAB, которые взаимодействуют с plotly.js. Компания также поддерживает веб-приложение для создания диаграмм и подключения их к базам данных (стыковочные библиотеки также распространяются с открытым исходным кодом).

    Если вы используете локальную версию с открытым исходным кодом, в таком случае ограничений нет. Вы можете управлять развёртыванием Dash-приложений самостоятельно через платформы вроде Heroku или Digital Ocean.

    Если вы ищите вдохновение для создания своих пользовательских интерфейсов в области технических вычислений, рекомендуем прочитать статью Брета Виктора

    Вам также может понравиться проект Explorable Explanations , который специализируется на интерактивном обучении.

    Данная статья посвящена трем важным в разработке приложений понятиям: Python, а также веб-серверам и наиболее важным их отличиям.

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

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

    Python Web Server Gateway Interface v1.0 (WSGI)

    На сегодняшний день количество взаимозаменяемых веб-серверов (или модулей для серверов), специально разработанных или адаптированных для размещения веб-приложений Python, постоянно растет. Но так было не всегда. Ранее разработчики не имели возможности легко сменить веб-сервер при необходимости, и каждый переход с одного сервера на другой означал новые зависимости и ограничения. Также это касалось фреймворков для разработки приложений. Это было связано с отсутствием общепринятых технических характеристик интерфейса (т.е., общей основы, которую будут использовать для соединения похожие фреймворки и веб-серверы, что обеспечивает взаимозаменяемость компонентов с минимальными изменениями кода).

    Появление стандарта

    В начале этого века были приложены все усилия, чтобы, наконец, представить публике Python Enhancement Proposal (PEP) 333.

    Из PEP (Python Enhancement Proposal) 333:

    This document specifies a proposed standard
    interface between web servers and Python web
    applications or frameworks, to promote web
    application portability across a variety of
    web servers.

    Как говорится в РЕР, этот новый стандарт обеспечивает переносимость между веб-серверами и веб-приложениями Python. Мощные функции данного стандарта и его широкое внедрение по сравнению с предыдущими серьезно повлияли на развитие серверов: на сегодняшний день существует много (возможно, даже слишком много) веб-серверов, готовых сделать всю работу самостоятельно.

    Сравнение

    В данном разделе, посвященном сравнению веб-серверов для приложений Python, речь пойдет о некоторых популярных доступных серверах. Цель данного раздела – дать читателю четкое представление о серверах и помочь подобрать соответствующий требованиям приложения сервер. В связи с огромным количеством веб-серверов, которое невозможно охватить в рамках одной статьи, далее будут описаны только «выдающиеся» серверы (т.е., наиболее популярные, наиболее надежные, или же обладающие более мощными функциями по сравнению с остальными машинами).

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

    Веб-серверы (в алфавитном порядке)

    CherryPy WSGI -сервер

    Что это такое?

    На самом деле, CherryPy – это фреймворк. Тем не менее, он полностью автономен (то есть, может работать сам по себе, в том числе на стадии производства, и не требует дополнительного программного обеспечения). Это осуществляется благодаря собственному веб-серверу WSGI, совместимому с HTTP/1.1. Проект CherryPy описывает его как «готовый к производству высокоскоростной общий HTTP-сервер». Поскольку это WSGI-сервер, он может обслуживать любое другое приложение Python WSGI, не привязываясь к фреймворку для разработки приложений CherryPy.

    • Он компактен и прост.
    • Он может обслуживать любые веб-приложения Python, работающие на WSGI.
    • Он может обрабатывать статические файлы, а также обслуживать файлы и папки.
    • Поставляется с поддержкой SSL.
    • Это легко адаптируемая, надежная и простая в использовании альтернатива Python.

    Gunicorn

    Что это такое?

    Gunicorn – автономный веб-сервер с обширной функциональностью, предоставленной в удобном виде. Он использует pre-fork модель (это значит, что что главный процесс управляет инициированными рабочими процессами различного типа, которые затем обрабатывают запросы). И все это можно настроить и адаптировать относительно потребностей проекта и разнообразных сценариев производства.

    Почему нужно рассмотреть возможность его использования?

    • Он поддерживает WSGI и может быть использован с любым приложением и фреймворком Python на основе WSGI.
    • Это также полноценная замена Paster (например, Pyramid), сервера разработки Django, web2py, и так далее.
    • Предлагает широкий выбор различных типов «исполнителей»/конфигураций и автоматическое управление рабочими процессами.
    • Поддерживает HTTP/1.0 и HTTP/1.1 с помощью синхронных и асинхронных исполнителей.
    • Поставляется с поддержкой SSL
      Расширяется с помощью специальных точек входа.
      Интуитивно понятен, имеет четкую архитектуру.

    Tornado (HTTP- сервер)

    Что это такое?

    Tornado – это фреймворк для разработки приложений и сетевая библиотека, созданная для обработки асинхронных операций, что позволяет таким серверам поддерживать большое множество открытых соединений. Поставляется с сервером WSGI, который могут использовать для запуска другие приложения и фреймворки WSGI Python.

    Почему нужно рассмотреть возможность его использования?

    • Необходим при работе с фреймворком Tornado;
    • Удобен для приложений, которым нужен асинхронный режим работы.

    Хотя, в таких случаях можно также использовать Gunicorn с асинхронными исполнителями Tornado.

    Twisted Web

    Что это такое?

    Twisted Web – это веб-сервер, который поставляется с сетевой библиотекой Twisted. Тогда как сама библиотека Twisted является «событийно-управляемым сетевым механизмом», сервер Twisted Web работает на WSGI, следовательно, может содержать другие веб-приложения Python.

    Почему нужно рассмотреть возможность его использования?

    • Это простой в использовании, надежный и зрелый продукт.
    • Может запускать приложения WSGI Python.
    • Может использоваться как фреймворк веб-сервера Python, что позволяет запрограммировать его на обслуживание пользовательского HTTP.
    • Простое и быстрое создание прототипа с помощью Python Scrips (.rpy), что выполняется по запросам HTTP.
    • Обладает возможностями прокси и инвертированного прокси-сервера.
    • Поддерживает Virtual Hosts.
    • Обслуживает Perl, PHP и т.п. через программный интерфейс приложения twisted.web.twcgi.

    uWSGI

    Что это такое?

    Несмотря на очень запутанное соглашение об именах, сам uWSGI является обширным проектом, который состоит из большого количества компонентов, которые предоставляют полный набор программного обеспечения для построения хостинговых услуг. Один из этих компонентов, сервер uWSGI, запускает приложения Python WSGI. Он может использовать различные протоколы, в том числе и собственный протокол uwsgi, идентичный SCGI. Поскольку автономные HTTP-серверы по сравнению с серверами приложений более популярны, веб-серверы NGINX и Cherokee разработаны как модульные, что позволяет uWSGI использовать собственный протокол с высокой производительностью и обеспечивает прямой контроль над процессами.

    Почему нужно рассмотреть возможность его использования?

    • Поставляется с адаптером WSGI и полностью поддерживает приложения Python на WSGI.
    • Связан с libpython. Он загружает код приложения при запуске и действует как интерпретатор Python, а также анализирует входящие запросы и вызывает Python.
    • Поставляется с прямой поддержкой популярного веб-сервера NGINX (а также Cherokee и Lighttpd).
    • Написан на языке C.
    • Различные компоненты могут сделать гораздо больше, чем просто запуск приложения, что может быть полезно для расширения функций.
    • В настоящее время (по состоянию на конец 2013 года), uWSGI активно развивается, регулярно появляются новые версии.
    • Имеет различные механизмы для запуска приложений (асинхронного и синхронного).
    • Невысокое потребление памяти при запуске.

    Waitress WSGI-сервер

    Что это такое?

    Waitress – это сервер Python WSGI. На первый взгляд может показаться, что он не обладает существенными отличиями, однако его философия разработки отделяет его от остальных серверов. Его целью является упрощение процессов разработки и производства, достаточно сложных на серверах Python. Для этого Waitress нейтрализует конфликты, вызванные различиями платформ (например, Unix vs. Windows), интерпретаторов (CPython vs. PyPy) и версий Python (версия 2 vs 3).

    Почему нужно рассмотреть возможность его использования?

    • Это очень простой, минималистский сервер Python.
    • Поддерживает HTTP/1.0 and HTTP/1.1 (Keep-Alive).
    • Поставляется готовым к развертыванию производства с широким спектром поддержки платформы.
    • В отличие от CherryPy, он по своей сути независим от фреймворка.
    • Запускается на Windows и Unix, работает с интерпретаторами CPython и PyPy (только на Unix).
    • Поддерживает версии Python 2 и 3.

    Модули для автономных серверов

    mod _ python с адаптером WSGI (Apache ) (встраивание Python )

    Простыми словами, mod_python – это модуль Apache, который встраивает Python непосредственно в сервер. Хотя использовать его не всегда рекомендуется, он может запускать приложения WSGI на Apache с помощью оболочек.