14 февраля 2010 в 21:56

Django в неблокирующем стиле, или в погоне за Священным Граалем

image

Присказка


При чтении о Twisted, Tornado, Node.js, у многих python-программистов возникает вопрос — «а вот если взять, и переписать Django в неблокирующем стиле?». Обычный ответ на этот вопрос — нет, не дождетесь. И правда, чтобы переписать целый фреймворк в макаронно-колбечном стиле, надо очень много сил, и большой заряд энтузиазма. Писать с колбеками, очень сомнительное удовольствие.

Так бы и было, но как я писал в своей прошлой заметке, есть в python-мире greenlet-ы, которые легким движением руки помогают скрыть от программиста все эти асинхронные моменты, до определенной степени. В момент написания той заметки, к мысли заставить работать Django в неблокирующем режиме, я относился весьма скептически — ну в самом деле, кто за это возьмется?



Суть


А на самом деле все не так страшно, следите за руками — мы создаем WSGI ресурс в Twisted, начинаем слушать HTTP-запросы; каждый запрос мы отдаем в WSGI-обработчик Django, оборачивая его в гринлет; любые запросы, которые можно преобразовать в неблокирующие, передаем Twisted, который пнет наш гринлет в момент готовности данных; готово!

image

А что же у нас есть такого, что можно обратить в неблокирующий режим в первую очередь? В Django основным таким местом выступает база данных. Можно ли с ней общаться асинхронно? Абсолютно верно, но нужен специальный драйвер.

С давних пор в Twisted есть такой — PGAsync. У него есть серьезные проблемы, он давно заброшен, но кто нам мешает подхватить упавшее знамя? Я сделал такую попытку, на данный момент драйвер работает стабильнее оригинала, но работа еще не закончена. Тем не менее, асинхронную БД для Django мы получить можем, и это будет Postgresql (ох, простите, пользователи Mysql, но кто вам мешает написать свой?). Драйвер используется в текущем проекте, разрабатываемом Imarto Networks imarto.net, и было решено выложить его для свободного использования. Я выложил его раньше готовности, только для демонстрации асинхронного Django, будьте снисходительны.

Чтобы использовать его в Django, нам надо написать свой БД-бэкенд. Я наворотил что-то из бэкенда для psycopg2, обернув обращения к драйверу БД в функции передачи управления главному гринлету, то есть основному потоку программы. Стандартный wsgi-ресурс из twisted.web пришлось тоже немного переделать, ведь он теперь должен кидать запросы на обработку не в пул потоков, а в гринлеты.

Как пощупать


Исходники можно получить тут, там же тестовый django-проект — bitbucket.org/deepwalker/tx_green
Исходники драйвера к БД — bitbucket.org/deepwalker/tx-postgresql

Для использования надо разместить pgasync, green_wsgi.py, tx_green.py, tx_postgresql в место, где интерпретатор сможет их найти. Затем в каталоге test_green_dj настраиваем параметры подключения к БД, ./manage.py syncdb, twistd -n — y server.py. Все, по адресу 127.0.0.1:8001 встречаем наш тестовый проект.

Про тесты


Тесты, которые я проводил, относились в основном к проверке работы, прироста производительности я не измерял. Если кто-то потратит свое время на это доброе дело, буду благодарен, если поделитесь результатами.
Кривушин Михаил @Deepwalker
карма
18,7
рейтинг 0,0
Программист
Похожие публикации
Самое читаемое Разработка

Комментарии (64)

  • +5
    omploader.org вас кинул )
    • 0
      Да что ж это такое? Срочно подскажите нормальный картинко-хостинг.
      • +1
        S3
      • +1
        У imageshack.us тоже есть ограничения.
        Используйте (да-да, опять реклама) pict.com, picasaweb.google.com, fotki.yandex.ru
      • 0
        fotki.ru
      • +1
        dropbox
    • 0
      он вернулся :)
  • 0
    Вам следует посмотреть на gevent/eventlet (оба используют greenlet). Они могут действовать следующим образом — производится замена стандартного модуля socket на неблокирующий (monkey-patching), и соответственно все библиотеки, которые используют python-сокеты становятся неблокирующими (к сожалению или к счастью к ним НЕ относится ни python-mysql ни psycopg2, но есть mysql-connector и pg8000).
    • 0
      Интересно, про pg8000 не слышал, спасибо.
    • 0
      Django я не пробовал так запускать, потому что не использую его, но вот SQLAlchemy прекрасно работает таким образом в неблокирующем стиле.
      • 0
        Можно Svarga тогда смело запускать, он на SQLAlchemy крутится. А для Django в любом случае надо будет написать свой БД бэкенд для pg8000 или mysql-connector, и тоже запустить, дело часа.
      • 0
        Кстати, нашел недостаток подхода, как мне кажется. В pgasync есть пул соединений. Когда вы запрашиваете соединение, то на самом деле ничего не происходит, интересное начнется только в момент получения курсора, из пула вам выделят соединение.

        Это решает проблему, что будет, если к вам придет 100 пользователей в секунду — получите ли вы 100 подключений к БД? По-моему это не очень хорошо. Второе это установка соединения — синхронный код ничего не знает о пуле, и вполне способен устанавливать соединение на каждый запрос.

        Это как раз момент, с которым я немного подвис с pgasync — думаю как лучше работать с пулом, когда возвращать подключение в пул.
  • –11
    Дык эта, Грааль нашли уже давно :-P
    • –2
      Какие же зануды эти питонисты…
  • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      Тут как раз предлагается вариант, когда усложнений в коде не появляется.
      • НЛО прилетело и опубликовало эту надпись здесь
        • 0
          Во-первых прекрасно понятно как — подводных камней нет, или по крайней мере с ними все понятно. А теперь начинаем считать стоимость разработки с нуля всего кода, что уже есть. Затем вспоминаем, что программирование на C++ это известный ужас, в сравнении с Python, и стоить будет еще дороже. Итак, пару дней на допил моего варианта, или всё с нуля, и с песнями, и еще кучу денег на зарплаты программистам, а дедлайн как нибудь потом?
    • НЛО прилетело и опубликовало эту надпись здесь
      • 0
        Что именно будет делать django в течении времени, когда происходит ввод/вывод?
        • НЛО прилетело и опубликовало эту надпись здесь
          • 0
            Как этого можно добиться, не переписывая все приложение с нуля? Как Вы будете реендерить страничку для другого пользователя, если приложение написано для работы в одном процессе?
            С другой стороны, у нас нет простоев и потерь времени на ожидание IO, потери у нас только на переключение контекста и порождение новых процессов, чтобы его минимизовать есть префорк. Выигрышь будет копейки. Единственное, где можно выиграть, ИМХО, в отдаче статики. Но это и так делается, через нгингс.
            • 0
              Есть же мультиплексоры ввода-вывода, такие как select, epoll, kqueue, с помощью них во время ожидания на I/O, можно выполнять другой код.

              Greenlet же это userspace поток, то есть вычисление, которое можно «заморозить», а потом продолжить. С помощью них реализуется вытесняющая многозадачность. Таким образом, в одном OS-процессе мы имеем несеолько greenlet'ов, по одному на каждый запрос например, во время ожидания одного greenlet'а на I/O, какой-то другой greenlet можеть продолжать выполнение, обслуживая другого пользователя.
              • 0
                Т.е. выигрыш должен получиться за счет меньшего потребления ресурсов на переключение greenlet-овских минипотоков, по сравнению потреблением ресурсов на переключение контекста процессов ОС?
                Мое мнение — на Win32 и Apache на процессах возможно имеет смысл, на UNIX/LINUX выигрыш должен быть небольшим. Но надо учитывать, что будет проигрыш в надежности.
                • 0
                  > Мое мнение — на Win32 и Apache на процессах возможно имеет смысл, на UNIX/LINUX выигрыш должен быть небольшим.
                  А какая разница?

                  > Но надо учитывать, что будет проигрыш в надежности.
                  Тоже непонятно откуда такой вывод.
                  • 0
                    — Разница в том, что в Win32 очень медленное порождение процессов, поэтому там все, что требует мало-мальской производительности должно быть на тредах.

                    — Потому, что уровень изоляции параллельных задач в тредах по определению хуже, чем в процессах. Главное, в случае фатальной ошибки в приложении на процессах рушится один процесс, то в приложении на тредах — все приложение.
                    • 0
                      Так мы же говорим о greenlet'ах, причём тут процессы?
                      • 0
                        А с чем сравниваем? ИМХО, с базовой реализацией/ обычной конфигурацией. А обычная конфигурация, это апач и каждый клиент обслуживается префоркнутым процессом апача.
                        Или я не понимаю вообще о чем мы говорим.
                        • 0
                          Вы, видимо, уже сравниваете prefork на Windows и prefork на Unix :-).
                          • 0
                            Виндовс: Префорк vs greenlets
                            UNIX: префорк vs greenlets
                            • 0
                              Переключение между greenlet'ами намного быстрее чем между процессами и даже потоками Windows/UNIX.
                              • 0
                                Возможно, толко это не технический термин — «намного»
                                При оценке выигрыша, нужно оценивать, имхо две вещи,
                                1) Доля выигрыша по скорости
                                2) Доля процессорного времени, которая идет на переключение в случае процессов

                              • 0
                                Кстати переключение между потоками и процесами на UNIX не сильно отличаются ИМХО.
              • +1
                Вытесняющая? Вы точно о гринлетах?
                • 0
                  Да извиняюсь, кооперативная, спасибо что поправили.
            • 0
              не только статика. nginx позволяет еще экономить на обработке медленных клиентов. nginx пока не получит всех необходимых данных не передает из далее по цепочке. Как результат нет процессов FastCGI которые ожидают завершения ввода/вывода.
              • +1
                Бла-бла-бла. Это давно уже все веб-серверы умеют, хватит повторять эту древнюю мантру.
                • 0
                  Ага только ресурсов они хавать могут больше.
                  • 0
                    Так всё-таки не только nginx позволяет, да?
                    • 0
                      А я таки говорил что это чисто фича nginx?
                      • 0
                        > nginx позволяет еще экономить

                        Видимо, да.
          • 0
            Запустить рядом еще одну джангу?
    • +10
      есть мнение, что С++ — редкостной неизящности язык. Скажем так, в нем десятки способов выстрелить себе в ногу. Помимо производительности у него больше особых плюсов не водится. Ах да, производительность… Тогда уж Java хотя бы.

      • +1
        К сожалению, ничего другого в настоящее время на горизонте не видно.
      • НЛО прилетело и опубликовало эту надпись здесь
        • +1
          Так, а вот про операционки — это вы поподробней. Какая из больших современны ОС написана на С++?

          Я вот искренне всегда думал про С.
          • НЛО прилетело и опубликовало эту надпись здесь
            • +1
              Linux: Most of the code (71%) was written in the C programming language.

              Windows — то же самое, может, процент плюсов чуть больше.

              На чистых плюсах написаны BeOS и WinCE / WinMobile
            • +2
              На C пишут, и очень много, вас кто-то ввел в заблуждение.
              • НЛО прилетело и опубликовало эту надпись здесь
            • 0
              Мы говорим про Веб. А в вебе Ява — языки под JVM — в определенных областях рулит. Например, резко масштабируемые приложения со Scala.

              В системных вещах непревзойден C; компиляторы/интерпретаторы тоже на нем пишутся.

              C++ — больше десктоп и верхний слой графических API в разных ОС. Ну и игры. Еще пишут, случается, штуки вроде поисковиков — я на собеседовании был, где такая работа подразумевалась.
      • НЛО прилетело и опубликовало эту надпись здесь
        • +1
          Черт, не понимаю, почему бы и нет? Чем django так элитарна, что ее нельзя заставить работать асинхронно? Почему бы не использовать асинхронность? Nginx сильно поиграл от нее? Tornado проиграл? Или быть может Node.js неюзабельный отстой? Давайте конкретно — чем плоха асинхронная Django? Да, она не даст вам скорости Node.js, так как Python в текущей реализации в C код не транслируется на лету, но выжать заветные 5-10% (и это чисто умозрительная прикидка), чем это плохо?
          По-моему гораздо наивнее начать переписывать код на C++.
          • 0
            Взяв немного фантазии, буханку хлеба и две спицы, можно сделать троллейбус. Но зачем? (с)
            • 0
              Цитата с неба как то опровергает все аргументы, которые были приведены в комментариях к этому топику? Или есть контраргументы в стиле «это хреново, потому что», и дальше технические, а не умозрительные, «мне кажется», аргументы?
    • +6
      Я вам страшную вещь скажу. В обычном веб-приложении 80% времени работы занимает ожидания ввода-вывода. И пусть ваше с++ приложение (разработанное в 10 раз дольше) работает не 0.5сек, а 0.05 — без того же самого неблокирующего ввода-вывода оно будет висеть и 5 секунд ждать ответа от базы.
      У с++ есть своя ниша, где он востребован — но для разработки надо очень хорошо представлять, где и какой инструмент применять, его ограничения и возможности их обхода.
    • 0
      Писать код не на C/C++ дешевле и быстрее. Если у вас миллион клиентов, то уже другие суммы у вас будут — то ли этот миллион обслужится сотней серверов, то ли тремяста серверами, по-моему разница на лицо. Если можно выжать еще 5-10 процентов, то это надо сделать, тем более, что это дешево и быстро.
  • НЛО прилетело и опубликовало эту надпись здесь
    • НЛО прилетело и опубликовало эту надпись здесь
  • НЛО прилетело и опубликовало эту надпись здесь
    • 0
      Если вы хорошо понимаете внутренности того и другого — ничего опасного не вижу. Фреймворк написан в потоко-безопасном стиле, и мои скромные познания подсказывают мне, что и с гринлетами проблемы не будет. Привет хитрецам со thread local!: )
      • НЛО прилетело и опубликовало эту надпись здесь
  • 0
    Посмотрите, может найдете что-нибудь полезное. code.google.com/p/coev/
    • 0
      Смотрел — не вижу почему обязательно надо прерывать выполнение надо в C-коде.

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