测试基本信息

主题:比较异步框架和同步框架在数据库IO操作的性能差异

python版本:python 3.8

数据库:mysql 8.0.27 (docker部署)

压测工具:locust

web框架:同步:flask 异步:starlette

请求并发量: 模拟10个用户

服务器配置: Intel(R) i7-12700F

客户端配置:Intel(R) i7-8700 3.20GHz

flask 同步框架

python中操作数据库通常使用ORM框架完成。flask 使用的ORM框架是大名鼎鼎的sqlalchemy,该框架是所有ORM框架中生态最完善的,但是sqlalchemy对异步的支持并不算友好,目前支持原生SQL操作。

定义表结构

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine, Column, Integer, String DB_URI = "mysql+pymysql://root:123456@127.0.0.1:3306/test"
engine = create_engine(DB_URI)
Base = declarative_base(engine) # SQLORM基类 class Student(Base):
__tablename__ = 'student' # 表名
id = Column(Integer, primary_key=True, autoincrement=True)
name = Column(String(50)) Base.metadata.create_all() # 将模型映射到数据库中

api接口

from flask import Flask, request
from sqlalchemy.orm import sessionmaker
from model import Student, engine, Base app = Flask(__name__) @app.route('/users')
def list_all():
session = sessionmaker(engine)() # 构建session对象
students = session.query(Student).all()
res = [stu.name for stu in students]
session.close()
return res @app.route("/user", methods=["POST"])
def create():
session = sessionmaker(engine)() # 构建session对象
student = Student(name='Tony') # 创建一个student对象
session.add(student) # 添加到session
session.commit() # 提交到数据库
session.close()
return {"res":"success"} if __name__ == '__main__':
app.run(port=8090, host="0.0.0.0")

接口调用

post请求

get 请求:

压测结果

并发量:225

starlette 异步框架

starlette 异步框架配套使用的ORM框架是 tortoise-orm。tortoise-orm 是一款方便、易用、可靠的异步ORM框架,文档:https://tortoise.github.io/

安装数据库

pip install tortoise-orm
pip install aiomysql

定义表结构

from tortoise import fields, models

class Users(models.Model):
id = fields.IntField(pk=True)
username = fields.CharField(max_length=20) def __str__(self) -> str:
return f"User {self.id}: {self.username}"

api接口

from model import Users
from starlette.applications import Starlette
from tortoise.contrib.starlette import register_tortoise
from starlette.requests import Request
from starlette.responses import JSONResponse
from uvicorn.main import run app = Starlette() # 查询记录
@app.route("/user", methods=["GET"])
async def list_all(_: Request):
users = await Users.all()
return JSONResponse({"users": [str(user) for user in users]}) # 创建记录
@app.route("/user", methods=["POST"])
async def create(request: Request):
body = await request.json
username = body.get("user_name")
user = await Users.create(username=username)
return JSONResponse({"ret":"success"}) # 表迁移
register_tortoise(app, db_url="mysql://root:123456@127.0.0.1:3306/test", modules={"models": ["model"]}, generate_schemas=True) if __name__ == "__main__":
run(app, host="0.0.0.0")

接口调用

post请求创建一个用户

get请求

压测结果

并发量:1496

性能对比

并发曲线图对比:

参数对比:

框架 数据库IO 延迟 纯框架无IO 文件IO
fastapi 225 47 ms 463 453
starlette 1496 6 ms 1539 1538

总结

在数据库读写方面,异步框架性能是同步框架的6倍,可以看出同步框架在数据库读写频繁时性能下降明显,几乎是无IO读写的一半,而异步框架在有数据库IO的情况下并发几乎保持不变。主要原因是在当前简单的场景下数据库读操作耗时少而连接释放耗时较多,异步编程非阻塞模型不等待,所以数据库连接释放耗时并不阻塞异步框架。下一篇比较redis IO的并发性能。

连载一系列关于python异步编程的文章。包括同异步框架性能对比、异步事情驱动原理等。首发微信公众号,欢迎关注第一时间阅读。

Python异步编程之web框架 异步vs同步 数据库IO任务压测对比的更多相关文章

  1. python高级编程之 web静态服务器

    返回固定数据 import socket def request_handler(new_client_socket): """ 响应客户端请求的核心函数 "& ...

  2. python异步编程之asyncio

    python异步编程之asyncio   前言:python由于GIL(全局锁)的存在,不能发挥多核的优势,其性能一直饱受诟病.然而在IO密集型的网络编程里,异步处理比同步处理能提升成百上千倍的效率, ...

  3. 异步编程之Promise(3):拓展进阶

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

  4. 异步编程之Promise(2):探究原理

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

  5. 200行自定义异步非阻塞Web框架

    Python的Web框架中Tornado以异步非阻塞而闻名.本篇将使用200行代码完成一个微型异步非阻塞Web框架:Snow. 一.源码 本文基于非阻塞的Socket以及IO多路复用从而实现异步非阻塞 ...

  6. Tornado----自定义异步非阻塞Web框架:Snow

    Python的Web框架中Tornado以异步非阻塞而闻名.本篇将使用200行代码完成一个微型异步非阻塞Web框架:Snow. 一.源码 本文基于非阻塞的Socket以及IO多路复用从而实现异步非阻塞 ...

  7. 150行代码搭建异步非阻塞Web框架

    最近看Tornado源码给了我不少启发,心血来潮决定自己试着只用python标准库来实现一个异步非阻塞web框架.花了点时间感觉还可以,一百多行的代码已经可以撑起一个极简框架了. 一.准备工作 需要的 ...

  8. 异步编程之Generator(1)——领略魅力

    异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2):探究原理 异步编程之Promise(3):拓展进阶 异步编程之Generator(1)--领略魅 ...

  9. (翻译)异步编程之Promise(1):初见魅力

    原文:https://www.promisejs.org/ by Forbes Lindesay 异步编程系列教程: (翻译)异步编程之Promise(1)--初见魅力 异步编程之Promise(2) ...

  10. net异步编程之await

    net异步编程之await 初探asp.net异步编程之await   终于毕业了,也顺利进入一家期望的旅游互联网公司.27号入职.放肆了一个多月没写代码,好方啊. 另外一下观点均主要针对于await ...

随机推荐

  1. 关于ul点击事件委托给li时的鼠标拖动问题

    网上查看后发现Click可以被两个事件触发:mouseUp与mouseDown,即点击和松开时都会触发一次. 随后当我从一个li点击拖动到其他li松开时,触发的事件对象因为冒泡变成了父元素ul,并非我 ...

  2. mongo操作数据库

    1.回顾 2.node + mongodb 2.1 安装mongodb 项目中既可以使用mongodb,但是推荐使用mongoose cnpm i mongoose@4 -S 2.2 连接数据库 一定 ...

  3. kubernetes核心实战(一)--- namespace

    kubernetes核心实战 1.资源创建方式 命令行创建 yaml文件创建 2.namespace 命名空间(namespace)是Kubernetes提供的组织机制,用于给集群中的任何对象组进行分 ...

  4. c语言趣味编程(4)抓交通肇事犯

    一.问题描述 一辆卡车违反交通规则,撞人后逃跑.现场有三人目击该事件,但都没有记住车号,只记下车号的一些特征. 甲说:牌照的前两位数字是相同的: 乙说:牌照的后两位数字是相同的,但与前两位不同: 丙是 ...

  5. 省市县树形结构打印-.netCore控制台程序

    using CityJson;using Dapper;using Newtonsoft.Json;{ using (var db = DbHelper.Db()) { //数据格式 //code_p ...

  6. ThreadLocal实现原理和使用场景

    ThreadLocal是线程本地变量,每个线程中都存在副本. 实现原理: 每个线程中都有一个ThreadLocalMap,而ThreadLocalMap中的key即是ThreadLocal.  内存泄 ...

  7. Golang defer使用

    学习于https://www.liwenzhou.com/posts/Go/function/的文章 1. defer的执行顺序类似于栈,"后进先出",也就是最先defer的语句最 ...

  8. Spring源码:Bean的生命周期(二)

    前言 让我们继续讲解Spring的Bean实例化过程.在上一节中,我们已经讲解了Spring是如何将Bean定义加入到IoC容器中,并使用合并的Bean定义来包装原始的Bean定义.接下来,我们将继续 ...

  9. Kubernetes Gateway API 深入解读和落地指南

    背景 Kubernetes Gateway API 是 Kubernetes 1.18 版本引入的一种新的 API 规范,是 Kubernetes 官方正在开发的新的 API,Ingress 是 Ku ...

  10. 【HTML-CSS】div中加入icon后input标签占用不满问题

    做登录表单时遇到了一个宽度控制不好的问题,放入图标后,input框总是无法正确的填满剩余空间(尺寸过大/过小) 原因是input元素和父元素div宽度都写死的问题 把父元素的高度删除,宽度改成max- ...