Pull to refresh

Comments 17

/* WSGIApplication((lambda li:[(route[0], lazy_loader(route[1])) for route in li])([ */

Глядя на такое, становится ясно что я «знаю» какой-то другой Питон.
Промазал с прошлым комментарием.
lambda-функция всё же лишняя, можно и проще:
application = WSGIApplication([(route[0], lazy_loader(route[1])) for route in [
  (r'/', 'handlers.MainPage'),
  (r'/search/', 'handlers.Search'),
  (r'/_ah/queue/sendmail', 'mail.SendMail'),
  (r'/_ah/queue/HeavyTask', 'tasks.HeavyTask'),
  ]], debug=os.environ.get('CURRENT_VERSION_ID').lower().startswith('dev'))
Это небольшие приятные мелочи питона (которых я пару месяцев назад тоже не знал) — фильтрование списков и lambda-функция, определённая в месте использования. О них очень хорошо написано в книге «Dive into python». В более привычном виде эта функция делает примерно следующее:
def process_list(li):
  result = []
  for route in li:
    result.append((route[0], lazy_loader(route[1])))
  return result
А разве оно всё грузится не из-за того что импортируется в main.py?
Именно, импорт множества модулей занимает довольно много времени. В обычном случае приложению на старте приходится импортировать все используемые где-либо модули. То есть даже если какой-то тяжелый модуль используется лишь в одном обработчике где-нибудь в taskqueue, пользователю всё равно придётся ждать, пока он подгрузится. Ленивый загрузчик позволяет не грузить его пока он не понадобится для обработки запроса.
ну так это не имеет никакого отношения к webapp, а исключительно к директивам import в main.py
если там импортировать только wsgi то никаких тормоов не будет.

под taskqueue вообще говоря можно и другой скрипт сделать, не main.

да и вообще, всё тяжёлое надо бы переносить на backend.

ну так это не имеет никакого отношения к webapp, а исключительно к директивам import в main.py
если там импортировать только wsgi то никаких тормоов не будет.

К webapp отношение самое непосредственное, в django, например, ленивая загрузка везде, где только возможно и для него подобные решения не нужны. WSGIApplication принимает вызываемые объекты в качестве аргументов, так что их все равно придется импортировать, с ленивой загрузкой или без нее.

под taskqueue вообще говоря можно и другой скрипт сделать, не main.

да и вообще, всё тяжёлое надо бы переносить на backend.

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

А уж если используются дополнительные возможности, то будет веселье еще то: в каждый скрипт прописать use_library, свое middleware, свои фильтры для django, конфигурацию и следить, чтоб все везде было одинаково… Количество лишнего кода будет больше, чем 15 строк загрузчика.

С этим же загрузчиком подобных проблем не возникает. Кроме того, пользователю, зашедшему на главную страницу и нарвавшемуся на старт инстанса не придется ждать, пока загрузятся, например, нужные лишь на странице регистрации модули регулярок, капчи и отправки почты.
Пардон, давно не юзал и запамятовал, что там нужны callable.
Но в любом случае — импорты делает не webapp а программист, и проблема подгрузки всего не ограничивается именно webappом.

Несколько точек входа никоим образом не вынуждает никого раскладывать модули в разные папки или ёщё как попало.
Если для задач или крона не нужны капчи и почта — можно просто не импортировать эти модули в скрипте.

Ну а так то да, естественно, ленивая загрузка упрощает жизнь.
Оригинальное решение, но, если честно, особого преимущества не даст. Как написано в официальной документации, в разделе Импорт кэшируется: «Для повышения эффективности веб-сервер сохраняет импортированные модули в памяти и не выполняет их повторную загрузку и анализ при последующих запросах от того же приложения на том же сервере.» Один раз загрузили, в другой раз отложенные вычисления = лишняя нагрузка, и никакой магии.
«Лишней нагрузки» в данном случае — небольшой перерасход памяти за счёт объектов-прослоек и этим спокойно можно пренебречь. Обработка одного списка при старте приложения тоже занимает совсем немного времени. Главная задача ленивого загрузчика — ускорить старт инстанса. И это ускорение достигается за счёт того, что модули импортируются только тогда, когда они нужны, а не все сразу при старте приложения.

«Размазывание» импорта на несколько запросов не ускоряет приложение чудесным образом, зато оно ускоряет выполнение самого медленного запроса. Маленькое приложение в 4 обработчика, приведённое в статье, не очень удачный пример. Зато приложение в полсотни модулей и полсотни обработчиков при грамотном разнесении обработчиков и использовании ленивой загрузки стартует в несколько раз быстрее. Плюс уменьшается потребление памяти за счёт того, что не держатся наготове всевозможные модули.
если новый инстанс приложения взлетел в другой части облака, то кэширование импортов не поможет.
Не спорю, но импорт модулей и выполнение кода и так отложенное. Будет работать только то, что реально вызывается. Если у вас 1000 модулей, а импортируются при выполнении 3, то и загрузится только 3 + зависимые. Если объявляются объекты, то это всё пролетит на раз, т.к. выполнение модулей и объявление типов работает быстро.

Короче говоря, использовать ленивые вычисления можно, но не уверен, что при аккуратной организации модулей вы получите от ленивого кода выгоду.
ну вот выше уже акцентировалось, что конкретно webapp, требующий при инициализации указания (импортированных) callable объектов — весьма ограничивает возможность аккуратной организации.
Скажите, чем вам нравится стандартный гугловский webapp? Ведь это же лоскутное одеяло — часть от Джанги, часть от WebOb. Нет удобного способа выставить куки (в т.ч. подписанные ключом), нет передачи сообщений между страницами. И вообще не хватает многих полезных штук, которые есть в других фреймворках из коробки. Плюс если вы уйдете от GAE, придется переписывать код. Я не предлагаю писать на Джанге (от нее там один огрызок), но flask, на мой взгляд, идеально подойдет.

Что касается ленивой загрузки приложения, то, на мой взгляд, описанный метод сложен и понятен вам одному. Я обычно разношу интерфейс и бекенд на разные скрипты. В скрипте интерфейса минимум импортов, поэтому сайт грузится быстро. Бекенд можно подогревать постоянными запросами по крону.
Скажите, чем вам нравится стандартный гугловский webapp? Ведь это же лоскутное одеяло — часть от Джанги, часть от WebOb. Нет удобного способа выставить куки (в т.ч. подписанные ключом), нет передачи сообщений между страницами. И вообще не хватает многих полезных штук, которые есть в других фреймворках из коробки.

Webapp позволяет быстро и с удобством разрабатывать разные приложения — от простеньких скриптов до полноценных сайтов. В нем практически ничего лишнего, но есть возможности для расширения функционала. Те же cookie ставятся легко и просто:
self.response.headers.add_header('Set-Cookie', 'a=b; path=/; expires=sometime; HttpOnly')

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

Плюс если вы уйдете от GAE, придется переписывать код. Я не предлагаю писать на Джанге (от нее там один огрызок), но flask, на мой взгляд, идеально подойдет.

GAE вообще слишком специфичен, чтобы разработанный под него код можно было сразу использовать. Свои API, свои ограничения — все это придется учитывать при переезде, либо намеренно не использовать возможности AE и держать неоптимальное, но готовое к переезду приложение.

Чем Flask не лоскутное одеяло? В чём преимущество Werkzeug + Jinja 2 относительно WebOb + Django? Только flask придется таскать из приложения в приложение, следить за обновлениями и надеяться, что разработчики не поломают совместимость с GAE. А webapp и django «всегда под рукой», оттестированы и готовы к работе, баги в них правятся без моего участия.

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

Один объект, два обработчика, полдюжины действий, ссылки на документацию и никаких хаков в коде. Да, функция __import__ относится к продвинутым функциям «не на каждый день», но используется способом, простейшим из возможных. В конце концов, код можно и просто скопипастить (он специально выложен одним куском) и наслаждаться ленивой загрузкой в ожидании просветления.
Если позволите, ещё пара кирпичей в огород flask (точнее, в огород схемы обработчиков в werkzeug):
@app.route("/")
def hello():
    return "Hello World!"

Функционально-ориентированный подход сильно ограничивает возможность использования своих декораторов. Если в webapp можно спокойно сохранить словарь с данными в self и сгенерировать страницу по шаблону в декораторе, то здесь такое не пройдет. Здесь есть ещё немного про сравнение схем.

Указание маршрутов в декораторе выглядит неплохо для маленького приложения, но в приложении побольше придется лазить по коду в поисках нужного обработчика (в то время, как в webapp его можно быстро найти, посмотрев в общий список). И о ленивом загрузчике в таком случае можно только мечтать — приложение на flask просто обязано быть маленьким.

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

Sign up to leave a comment.

Articles