#python #flask #mod-wsgi
#python #flask #mod-wsgi
Вопрос:
У меня есть приложение Flask, работающее под управлением mod_wsgi, которое устанавливает соединение с базой данных. В этом приложении запущено несколько процессов (только один поток на процесс) и одно подключение к базе данных для каждого из этих процессов.
В настоящее время у меня есть что-то вроде этого:
myapp_wsgi.py
import myapp
app = myapp.setup()
def application(environ, start_response):
return app(environ, start_response)
myapp.py
from flask import Flask
app = Flask(__name__)
db = None
def setup():
global db
db = get_db()
# Other setup
return app
@app.route("/")
def index():
data = db.get_data()
return data
Теперь использование глобальных переменных здесь выглядит не очень хорошо. Если бы приложение было классом, я мог бы использовать self.db
, но это не так. Есть ли лучший, более питонический, более похожий на Flask способ сделать это?
Ответ №1:
Я полагаю, это будет зависеть от базы данных (и ORM), с которой вы используете. Если вы используете SQLAlchemy или flask-sqlalchemy
(что я настоятельно рекомендую вам сделать), вы обычно определяете одну глобальную переменную для подключения к базе данных. Обычно это настраивается в init_app()
-function . Если вы посмотрите на код настройки приложения, вы увидите, что довольно часто основным объектом приложения flask является глобальная переменная app
. Очень часто вы обнаружите объект базы данных в качестве глобальной переменной db
, которая часто импортируется вместе с app
другими частями приложения.
Вы должны взглянуть на документацию по приложению и контексту запроса и особенно на местоположение контекста, в котором объясняется, как это работает. По сути, контекст никогда не разделяется между запросами (и, следовательно, потоками), поэтому не должно быть условий гонки и проблем.
Кроме того, global
ключевое слово в вашем случае не обязательно. Дело в том, что вы никогда не измените содержимое переменной db
. Это объект, который управляет подключением к базе данных, и вы вызываете только те методы, которые он предлагает. global
Ключевое слово необходимо, когда вы хотите изменить содержимое переменной, присвоив ей новое значение.
Итак, я бы реорганизовал setup()
следующим образом (и предпочтительно поставил это __init__.py
, чтобы его можно было легко импортировать)
from flask import Flask
def setup():
app = Flask(__name__)
db = get_db() #This is a local variable now
# whatever else needs to be done
return app, db
app, db = setup()
А затем в mod_wsgi.py
from myapp import app
def application(environ, start_response):
return app(environ, start_response)
Ответ №2:
Что касается совместного использования состояния между потоками wsgi, существует директива, которую вы можете поместить в конфигурацию виртуального хоста apache, которая позволяет им выполняться в одном контексте.
Директива WSGIApplicationGroup может использоваться для указания, к какой группе приложений принадлежит приложение WSGI или набор приложений WSGI. Все приложения WSGI в одной и той же группе приложений будут выполняться в контексте одного и того же субинтерпретатора Python процесса, обрабатывающего запрос.
Обратите внимание, что это для потоков внутри процесса, а не между процессами.