Понимание устойчивости глобальных объектов в приложениях Python WSGI - PullRequest
12 голосов
/ 17 ноября 2011

Рассмотрим следующий код в моем приложении WebApp2 в Google App Engine:

count = 0

class MyHandler(webapp2.RequestHandler):

    def get(self):

        global count
        count = count + 1
        print count

С каждым обновлением страницы счетчик увеличивается.

Я из мира PHP, где каждый запрос был новой глобальной средой. Я понимаю, что здесь происходит, потому что я использую конфигурацию wsgi для WebApp2, Python не запускает новый процесс при каждом запросе. Если бы я использовал конфигурацию cgi, с другой стороны, глобальная среда каждый раз создавала бы новые экземпляры, как PHP ...

Предполагая, что вышеприведенное верно (если нет, пожалуйста, исправьте меня) ...

  1. Как я могу обработать сценарии, в которых я хотел бы, чтобы глобальная переменная сохранялась только в течение срока действия запроса? Я мог бы поместить переменную экземпляра в класс RequestHandler, но как насчет таких вещей, как служебные модули, которые я импортирую, которые используют глобальные переменные для таких вещей, как хранение объекта сообщения?
  2. Существует ли какая-то техника сброса всех переменных или принудительного повторного создания среды?
  3. Глобальная среда сохраняется бесконечно или в какой-то момент она сбрасывается?
  4. Является ли какой-либо из этих GAE специфичным, или глобальная устойчивость wsgi работает одинаково в любом серверном сценарии?

EDIT:

Вот попытка использования threadlocal:

count = 0

mydata = threading.local()
mydata.count = 0

class MyHandler(webapp2.RequestHandler):

    def get(self):

        global count
        count = count + 1
        print count

        mydata.count = mydata.count + 1
        print mydata.count

Они также увеличиваются между запросами

Ответы [ 3 ]

16 голосов
/ 18 ноября 2011

Ваше понимание верно. Если вы хотите, чтобы переменные сохранялись в течение всего запроса, вам не следует делать их глобальными - делайте их переменными экземпляра в вашем классе RequestHandler, доступ к которому осуществляется как self.var. Поскольку для каждого запроса создается новый RequestHandler, ваши переменные будут сохраняться ровно столько времени, сколько вам нужно. Глобальных переменных лучше избегать, если вам действительно не нужна глобальная (в отличие от конкретной) область.

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

4 голосов
/ 17 ноября 2011

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

Вполне возможно создать глобальную переменную, которая будет отличаться для каждого запроса. Это делается во многих рамках, и людям это нравится. Способ сделать это зависит от сервера. Большинство серверов используют «один поток на запрос», и я думаю, что GAE делает то же самое. В этом случае вы можете использовать переменную локального потока . Если вас беспокоит то, что это значение остается между запросами в этом потоке, вам понадобится некоторый код управления, который может подключиться к началу / концу запроса. Промежуточное программное обеспечение WSGI является хорошим местом для этого, если инфраструктура WebApp2 не обеспечивает хороший способ сделать это.

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

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

2 голосов
/ 27 ноября 2011

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

С другой стороны, это также полезно webapp2.WSGIApplication.registry . В этом случае экземпляры сохраняются между запросами и могут совместно использоваться (и повторно использоваться) для любых нужд вашего приложения в течение срока службы приложения, избегая создания экземпляров в глобальной области.

...