【问题标题】:FastAPI sharing SQLAlchemy session across threads when using synchronous functions使用同步函数时,FastAPI 跨线程共享 SQLAlchemy 会话
【发布时间】:2023-03-04 08:59:02
【问题描述】:

关于普通def 路径操作函数、依赖项和 SQLAlchemy 的菜鸟问题。在此处引用示例:https://fastapi.tiangolo.com/tutorial/sql-databases/#create-a-dependency,其中数据库会话在get_db()(同步)中创建并在create_user()(同步)中使用。根据https://fastapi.tiangolo.com/async/#very-technical-details,同步依赖和路径操作函数在线程池中执行,这是否意味着同一个数据库会话对象在两个不同的线程之间有效共享(假设它不是跨依赖重用的同一个线程和路径操作函数)?由于 SQLAlchemy 会话不是线程安全的,这可能有问题吗?

我可能完全误解了它是如何工作的,所以任何澄清都将不胜感激。

谢谢!

编辑:在考虑了更多之后,我认为这应该没问题,因为会话是按顺序(而不是同时)访问的,即使它可能由两个不同的线程访问。但我假设像下面这样使用session 会有问题?

async def func(s: Session):
  loop = asyncio.get_running_loop()
  await loop.run_in_executor(None, some_func, s)
  await loop.run_in_executor(None, some_other_func, s)
  ...

【问题讨论】:

    标签: multithreading sqlalchemy fastapi


    【解决方案1】:

    是的 Session 对象不是线程安全的,但是在 SQLAlchemy 中你实际上有多个连接,因为 SQLAlchemy 有一个default 的连接池系统,所以你定义的每个其他 SessionLocal 都会有自己的连接

    def get_db():
        db = SessionLocal()
        try:
            yield db
        finally:
            db.close()
    

    所以,没有共享连接,一切都是分开的,SessionLocal 也在请求后关闭。所以它不是线程安全的,但我认为这不会有问题。

    假设您有一个端点,它同时收到 2 个请求,因此在这种情况下,不同的连接将响应您的请求。即使它不是并发的,它的作用就像与 Pooling 并发一样。

    【讨论】:

    • 感谢您的回答!所以我遇到的问题并不是关于单个会话是否由两个请求共享(正如您在上面解释的那样,不是),而是单个会话是否由处理相同请求的两个线程共享(并认为他们这样做但应该没问题,因为访问是顺序的)。
    • @ljiatu Ups,我认为this 会完美地解释这些事情,如果不是,我会再努力:)
    • 是的,我以前读过,所以我认为这意味着我在问题末尾的示例不安全,对吗?
    • 没错,如果您想要线程安全会话,请查看scoped_sessions
    猜你喜欢
    • 2015-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-28
    • 2014-08-13
    • 1970-01-01
    • 2011-02-21
    • 1970-01-01
    相关资源
    最近更新 更多