Python 3.x 博士后、sqlalchemy和多重处理
我对python多处理比较陌生,并且正在努力解决与此主题相关的许多问题。我的最新问题是来自多处理、sqlalchemy和postgres的组合。有了这个组合,我有时会得到一个Python 3.x 博士后、sqlalchemy和多重处理,python-3.x,postgresql,sqlalchemy,multiprocessing,Python 3.x,Postgresql,Sqlalchemy,Multiprocessing,我对python多处理比较陌生,并且正在努力解决与此主题相关的许多问题。我的最新问题是来自多处理、sqlalchemy和postgres的组合。有了这个组合,我有时会得到一个 sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) SSL error: decryption failed or bad record mac 经过研究,我在文档中发现了以下提示: “这很关键 当使用连接池时,扩展到使用 通过create_Engi
sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) SSL error: decryption failed or bad record mac
经过研究,我在文档中发现了以下提示:
“这很关键
当使用连接池时,扩展到使用
通过create_Engine()创建的引擎,池连接
未共享到分叉进程。TCP连接表示为
文件描述符,通常跨流程边界工作,
这意味着这将导致对上的文件描述符的并发访问
代表两个或多个完全独立的Python解释器状态
有两种方法可以解决这个问题
第一个是,在子进程中创建一个新引擎,或者
在现有引擎上,在子引擎之前调用Engine.dispose()
进程使用任何连接。这将删除所有现有连接
池中的连接,以便它创建所有新的连接。”
这是:
“问题最终是uwsgi的分叉
当使用主进程处理多个进程时,uwsgi
在主进程中初始化应用程序,然后复制
应用程序转移到每个辅助进程。问题是如果打开
数据库连接在初始化应用程序时
多个进程共享同一连接,这会导致错误
上面。”
我的解释是,当使用多处理时,我必须确保每个进程都使用一个新引擎。
在我的子进程中,只有一个类可以读写postgres db,因此我决定在该类中定义一个slqalchemy引擎:
class WS_DB_Booker():
def __init__(self):
engine_inside_class = create_engine(botpak.bas.dontgitp.bot_engine_string)
Base_inside_class = declarative_base()
Base_inside_class.metadata.create_all(engine_inside_class)
session_factory_inside_class = sessionmaker(bind=engine_inside_class)
self.DBSession_inside_class = scoped_session(session_factory_inside_class)
def example_method_to_read_from_db(self):
try:
sql_alc_session = self.DBSession_inside_class()
sql_alc_session.query(and_so_on....
这在第一次试验中效果良好,没有任何问题。但我不确定这是在类中定义引擎的正确方法,还是会导致任何问题?如何分叉进程或哪个组件进行分叉实际上是不可理解的 您需要确保的是在分叉之后实例化
WS\u DB\u Broker
类强>
如果使用错误的方法(在fork之前实例化),则引擎可能已经在其池中引用了一些dbapi
连接。请参阅SQLAlchemy
为了使您的错误更加明显,您可以执行以下操作:
我在分叉之后实例化这个类。我的问题更关心的是在类中定义引擎。如果您可以确保在程序的整个生命周期中只实例化一次类,那么就可以了。否则,你必须以某种方式确保你做到了。
import os
class WS_DB_Booker():
def __init__(self):
# Remember the process id from the time of instantiation. If the
# interpreter is forked then the output of `os.getpid()` will change.
self._pid = os.getpid()
engine_inside_class = create_engine(botpak.bas.dontgitp.bot_engine_string)
Base_inside_class = declarative_base()
Base_inside_class.metadata.create_all(engine_inside_class)
session_factory_inside_class = sessionmaker(bind=engine_inside_class)
self._session = scoped_session(session_factory_inside_class)
def get_session():
if self._pid != os.getpid():
raise RuntimeError("Forked after instantiating! Please fix!")
return self._session()
def example_method_to_read_from_db(self):
try:
sql_alc_session = self.get_session()
# ^^^^^^^^^^^^^
# this may throw RuntimeError when used incorrectly, thus saving you
# from your own mistake.
sql_alc_session.query(and_so_on....