flask使用了blueprint或者restful情况下,scoped_session 创建一个线程安全的会话 with app.app_context()的平替

我的项目后端是python-flask框架,使用了flask-restx来开发RESTful API。
前几天遇到一个问题:想要在restx的某个命名空间中调用多线程来批量提交数据库。但是报错了,显示需要使用 with app.app_context() 来设置一个上下文。
但是我的项目采用工程模式创建flask app实例。并且在使用了 flask-restx 命名空间的情况下,如果模块需要调用with app.app_context()是无法实现的。会触发循环导入。

推荐使用SQLAlchemy的 scoped_session 来创建一个线程安全的会话:

from sqlalchemy import create_engine
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.orm import DeclarativeBase, sessionmaker, scoped_session

# 定义基类
class Base(DeclarativeBase):
    pass

# 创建数据库引擎
engine = create_engine() # 数据库的连接配置

# 创建线程安全的会话
db_session = scoped_session(sessionmaker(bind=engine))

# 初始化 SQLAlchemy
db = SQLAlchemy(model_class=Base)

def init_db(app):
	#app.config... # 数据库配置
    db.init_app(app)
    db.session = db_session # 绑定session到app

这样在blueprint或者restx namespace中,将之前的db操作换成db_session即可(以下代码做了脱敏):
测试了以下10w条数据,一次性插入的时间大约为90秒,分10个线程各自插入1w条,下降到22秒左右,整体耗时减少了75%。

from flask_restx import Resource, Namespace
from db import db_session
import time,
from threading import Thread


api = Namespace()

@api.route('/')
class AddToDB(Resource):
    def get(self):
        start = int(time.time())
        result = {}
        insert_num = 100000
        threads = []
        for i in range(10):
            thread = Thread(target=lambda: self.insert())
            threads.append(thread)
            thread.start()
        
        for thread in threads:
            thread.join()

        print(f'插入{insert_num}一共用时: {int(time.time()) - start}')
        return result

    def insert(self):
        session = db_session()
        try:
            for j in range(10000):
                new_item = item()
                session.add(new_item)
            session.commit()
        except Exception as e:
            session.rollback()
            print(f'数据库操作出错: {e}')
        return

db_session()比db.session有以下区别:

  1. 它是线程安全的,并且可以在多线程环境中使用。
  2. 不自动绑定到 Flask 应用上下文,因此可以在请求之外的代码中使用,例如在多线程任务。
  3. 需要手动调用 commit() 或 rollback() 来提交或回滚事务。
  4. 自动管理会话的生命周期,不需要在每个线程结束后手动关闭会话。
  • 7
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值