首页 后端开发 Python教程 最大限度地提高 FastAPI 效率:使用 py-cachify 极快地实现缓存和锁定

最大限度地提高 FastAPI 效率:使用 py-cachify 极快地实现缓存和锁定

Dec 05, 2024 am 05:47 AM

Maximize Your FastAPI Efficiency: Blazingly Fast Implementation of Caching and Locking with py-cachify

在快节奏的 Web 开发世界中,性能至关重要。高效的缓存机制可以通过减少冗余计算和数据库查询来显着增强 API 的响应能力。在本文中,我们将探讨如何使用 SQLModel 和 Redis 将 py-cachify 库集成到 FastAPI 应用程序中,以实现缓存和并发控制。

目录:

  • 简介
  • 项目设置
  • 使用 SQLModel 创建数据库模型
  • 构建 FastAPI 端点
  • 缓存端点结果
  • 锁定更新端点的执行
  • 运行应用程序
  • 结论

介绍

缓存是一种强大的技术,通过存储昂贵操作的结果并从快速访问存储中提供它们来提高 Web 应用程序的性能。借助 py-cachify,我们可以无缝地将缓存添加到 FastAPI 应用程序中,并利用 Redis 进行存储。此外,py-cachify 提供并发控制工具,防止关键操作期间出现竞争情况。

在本教程中,我们将逐步在 FastAPI 应用程序中设置 py-cachify 库,并使用用于 ORM 的 SQLModel 和用于缓存的 Redis。

项目设置

让我们从设置项目环境开始。

先决条件

  • Python 3.12
  • 诗歌(您可以使用任何您喜欢的包管理器)
  • 本地运行或远程访问的Redis服务器

安装依赖项

通过诗歌开始一个新项目:

# create new project
poetry new --name app py-cachify-fastapi-demo

# enter the directory
cd py-cachify-fastapi-demo

# point poetry to use python3.12
poetry env use python3.12

# add dependencies
poetry add "fastapi[standard]" sqlmodel aiosqlite redis py-cachify
登录后复制
登录后复制
登录后复制
  • FastAPI:用于构建 API 的 Web 框架。
  • SQLModel aiosqlite:结合 SQLAlchemy 和 Pydantic 进行 ORM 和数据验证。
  • Redis:用于与 Redis 交互的 Python 客户端。
  • py-cachify:缓存和锁定实用程序。

初始化 py-cachify

在使用 py-cachify 之前,我们需要使用 Redis 客户端对其进行初始化。我们将使用 FastAPI 的寿命参数来完成此操作。

# app/main.py
from contextlib import asynccontextmanager
from fastapi import FastAPI
from py_cachify import init_cachify
from redis.asyncio import from_url


@asynccontextmanager
async def lifespan(_: FastAPI):
    init_cachify(
        # Replace with your redis url if it differs
        async_client=from_url('redis://localhost:6379/0'),
    )
    yield


app = FastAPI(lifespan=lifespan)
登录后复制
登录后复制
登录后复制

在生命周期内,我们:

  • 创建异步 Redis 客户端。
  • 使用此客户端初始化 py-cachify。

使用 SQLModel 创建数据库模型

我们将创建一个简单的用户模型来与我们的数据库交互。

# app/db.py
from sqlmodel import Field, SQLModel


class User(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    name: str
    email: str
登录后复制
登录后复制

设置数据库引擎并在生命周期函数中创建表:

# app/db.py

# Adjust imports
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine


# Add the following at the end of the file
sqlite_file_name = 'database.db'
sqlite_url = f'sqlite+aiosqlite:///{sqlite_file_name}'
engine = create_async_engine(sqlite_url, echo=True)
session_maker = async_sessionmaker(engine)


# app/main.py
# Adjust imports and lifespan function
from sqlmodel import SQLModel

from .db import engine


@asynccontextmanager
async def lifespan(_: FastAPI):
    init_cachify(
        async_client=from_url('redis://localhost:6379/0'),
    )
    # Create SQL Model tables
    async with engine.begin() as conn:
        await conn.run_sync(SQLModel.metadata.create_all)

    yield
登录后复制
登录后复制

注意:为了简单起见,我们使用 SQLite,但您可以使用 SQLAlchemy 支持的任何数据库。

构建 FastAPI 端点

让我们创建端点来与我们的用户模型交互。

# create new project
poetry new --name app py-cachify-fastapi-demo

# enter the directory
cd py-cachify-fastapi-demo

# point poetry to use python3.12
poetry env use python3.12

# add dependencies
poetry add "fastapi[standard]" sqlmodel aiosqlite redis py-cachify
登录后复制
登录后复制
登录后复制

缓存端点结果

现在,让我们缓存 read_user 端点的结果,以避免不必要的数据库查询。

端点代码将如下所示:

# app/main.py
from contextlib import asynccontextmanager
from fastapi import FastAPI
from py_cachify import init_cachify
from redis.asyncio import from_url


@asynccontextmanager
async def lifespan(_: FastAPI):
    init_cachify(
        # Replace with your redis url if it differs
        async_client=from_url('redis://localhost:6379/0'),
    )
    yield


app = FastAPI(lifespan=lifespan)
登录后复制
登录后复制
登录后复制

使用@cached装饰器:

  • 我们使用 user_id 指定一个唯一的键。
  • 将 TTL(生存时间)设置为 5 分钟(300 秒)。
  • 5 分钟内使用相同 user_id 调用此端点将返回缓存的结果。

更新时重置缓存

当用户的数据更新时,我们需要重置缓存以确保客户端收到最新的信息。为了实现这一点,让我们修改 update_user 端点。

# app/db.py
from sqlmodel import Field, SQLModel


class User(SQLModel, table=True):
    id: int | None = Field(default=None, primary_key=True)
    name: str
    email: str
登录后复制
登录后复制

通过调用 read_user.reset(user_id=user_id),我们:

  • 清除特定user_id的缓存数据。
  • 确保后续 GET 请求从数据库获取新数据。

在下面,缓存的装饰器动态包装您的函数,添加 .reset 方法。此方法模仿函数的签名和类型,这样根据原始函数,它将是同步或异步的,并且将接受相同的参数。

.reset 方法使用缓存装饰器中定义的相同密钥生成逻辑来识别要使哪个缓存条目无效。例如,如果您的缓存键模式是 user-{user_id},则调用await read_user.reset(user_id=123) 将专门定位并删除 user_id=123 的缓存条目。

锁定更新端点的执行

为了防止更新期间的竞争条件,我们将使用一次装饰器来锁定更新端点的执行。

# app/db.py

# Adjust imports
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine


# Add the following at the end of the file
sqlite_file_name = 'database.db'
sqlite_url = f'sqlite+aiosqlite:///{sqlite_file_name}'
engine = create_async_engine(sqlite_url, echo=True)
session_maker = async_sessionmaker(engine)


# app/main.py
# Adjust imports and lifespan function
from sqlmodel import SQLModel

from .db import engine


@asynccontextmanager
async def lifespan(_: FastAPI):
    init_cachify(
        async_client=from_url('redis://localhost:6379/0'),
    )
    # Create SQL Model tables
    async with engine.begin() as conn:
        await conn.run_sync(SQLModel.metadata.create_all)

    yield
登录后复制
登录后复制

曾经:

  • 我们根据user_id锁定功能。
  • 如果另一个请求尝试同时更新同一用户,它将立即返回带有 226 IM 已使用 状态代码的响应。
  • 这可以防止同时更新导致数据不一致。

(可选)您可以配置 @once 以引发异常或在已获取锁的情况下返回特定值。

运行应用程序

现在是时候运行和测试我们的应用程序了!

1) 启动 Redis 服务器:

确保您的 Redis 服务器在本地运行或可远程访问。您可以使用 Docker 启动本地 Redis 服务器:

# app/main.py

# Adjust imports
from fastapi import Depends, FastAPI
from sqlalchemy.ext.asyncio import AsyncSession

from .db import User, engine, session_maker


# Database session dependency
async def get_session():
    async with session_maker() as session:
        yield session


app = FastAPI(lifespan=lifespan)


@app.post('/users/')
async def create_user(user: User, session: AsyncSession = Depends(get_session)) -> User:
    session.add(user)
    await session.commit()
    await session.refresh(user)
    return user


@app.get('/users/{user_id}')
async def read_user(user_id: int, session: AsyncSession = Depends(get_session)) -> User | None:
    return await session.get(User, user_id)


@app.put('/users/{user_id}')
async def update_user(user_id: int, new_user: User, session: AsyncSession = Depends(get_session)) -> User | None:
    user = await session.get(User, user_id)
    if not user:
        return None

    user.name = new_user.name
    user.email = new_user.email

    session.add(user)
    await session.commit()
    await session.refresh(user)

    return user
登录后复制

2) 运行 FastAPI 应用程序:

一切设置完毕后,您可以使用 Poetry 启动 FastAPI 应用程序。导航到项目的根目录并执行以下命令:

# app/main.py

# Add the import
from py_cachify import cached


@app.get('/users/{user_id}')
@cached('read_user-{user_id}', ttl=300)  # New decorator
async def read_user(user_id: int, session: AsyncSession = Depends(get_session)) -> User | None:
    return await session.get(User, user_id)
登录后复制

3) 测试和使用缓存和锁定:

缓存: 在 read_user 函数中添加延迟(例如,使用 asyncio.sleep)以模拟长时间运行的计算。观察结果缓存后响应时间如何显着改善。

示例:

# create new project
poetry new --name app py-cachify-fastapi-demo

# enter the directory
cd py-cachify-fastapi-demo

# point poetry to use python3.12
poetry env use python3.12

# add dependencies
poetry add "fastapi[standard]" sqlmodel aiosqlite redis py-cachify
登录后复制
登录后复制
登录后复制

并发和锁定:同样,在 update_user 函数中引入延迟,以观察并发更新尝试时锁的行为。

示例:

# app/main.py
from contextlib import asynccontextmanager
from fastapi import FastAPI
from py_cachify import init_cachify
from redis.asyncio import from_url


@asynccontextmanager
async def lifespan(_: FastAPI):
    init_cachify(
        # Replace with your redis url if it differs
        async_client=from_url('redis://localhost:6379/0'),
    )
    yield


app = FastAPI(lifespan=lifespan)
登录后复制
登录后复制
登录后复制

这些延迟可以帮助您了解缓存和锁定机制的有效性,因为由于缓存,后续读取应该更快,并且应该通过锁定有效管理对同一资源的并发写入。

现在,您可以使用 Postman 等工具或访问 http://127.0.0.1:8000/docs(当应用程序运行时!)来测试端点,并观察性能改进和并发控制的实际情况。

享受使用增强型 FastAPI 应用程序进行实验的乐趣!

结论

通过将 py-cachify 集成到我们的 FastAPI 应用程序中,我们释放了众多优势,增强了 API 的性能和可靠性。

让我们回顾一下一些关键优势:

  • 增强的性能:缓存重复的函数调用可以减少冗余计算和数据库命中,从而大大缩短响应时间。
  • 并发控制:通过内置锁定机制,py-cachify 可以防止竞争条件并确保数据一致性 - 对于高并发访问的应用程序至关重要。
  • 灵活性:无论您使用同步还是异步操作,py-cachify 都能无缝适应,使其成为现代 Web 应用程序的多功能选择。
  • 易于使用:该库与 FastAPI 等流行的 Python 框架顺利集成,让您可以轻松上手。
  • 完整类型注释: py-cachify 具有完全类型注释,有助于以最小的努力编写更好、更易于维护的代码。
  • 最小设置: 如本教程所示,添加 py-cachify 只需要在现有设置之上添加几行即可充分利用其功能。

对于那些渴望进一步探索的人,请查看py-cachify 的 GitHub 存储库官方文档以获取更深入的指导、教程和示例。

您可以在 GitHub 此处访问本教程的完整代码。请随意克隆存储库并尝试实现以满足您项目的需求。

如果您发现 py-cachify 有益,请考虑在 GitHub 上给它一颗星来支持该项目!您的支持有助于推动进一步的改进和新功能。

编码愉快!

以上是最大限度地提高 FastAPI 效率:使用 py-cachify 极快地实现缓存和锁定的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

<🎜>:泡泡胶模拟器无穷大 - 如何获取和使用皇家钥匙
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系统,解释
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

热门话题

Java教程
1664
14
CakePHP 教程
1423
52
Laravel 教程
1319
25
PHP教程
1269
29
C# 教程
1248
24
Python vs.C:申请和用例 Python vs.C:申请和用例 Apr 12, 2025 am 12:01 AM

Python适合数据科学、Web开发和自动化任务,而C 适用于系统编程、游戏开发和嵌入式系统。 Python以简洁和强大的生态系统着称,C 则以高性能和底层控制能力闻名。

2小时的Python计划:一种现实的方法 2小时的Python计划:一种现实的方法 Apr 11, 2025 am 12:04 AM

2小时内可以学会Python的基本编程概念和技能。1.学习变量和数据类型,2.掌握控制流(条件语句和循环),3.理解函数的定义和使用,4.通过简单示例和代码片段快速上手Python编程。

Python:游戏,Guis等 Python:游戏,Guis等 Apr 13, 2025 am 12:14 AM

Python在游戏和GUI开发中表现出色。1)游戏开发使用Pygame,提供绘图、音频等功能,适合创建2D游戏。2)GUI开发可选择Tkinter或PyQt,Tkinter简单易用,PyQt功能丰富,适合专业开发。

Python与C:学习曲线和易用性 Python与C:学习曲线和易用性 Apr 19, 2025 am 12:20 AM

Python更易学且易用,C 则更强大但复杂。1.Python语法简洁,适合初学者,动态类型和自动内存管理使其易用,但可能导致运行时错误。2.C 提供低级控制和高级特性,适合高性能应用,但学习门槛高,需手动管理内存和类型安全。

Python和时间:充分利用您的学习时间 Python和时间:充分利用您的学习时间 Apr 14, 2025 am 12:02 AM

要在有限的时间内最大化学习Python的效率,可以使用Python的datetime、time和schedule模块。1.datetime模块用于记录和规划学习时间。2.time模块帮助设置学习和休息时间。3.schedule模块自动化安排每周学习任务。

Python vs.C:探索性能和效率 Python vs.C:探索性能和效率 Apr 18, 2025 am 12:20 AM

Python在开发效率上优于C ,但C 在执行性能上更高。1.Python的简洁语法和丰富库提高开发效率。2.C 的编译型特性和硬件控制提升执行性能。选择时需根据项目需求权衡开发速度与执行效率。

Python:自动化,脚本和任务管理 Python:自动化,脚本和任务管理 Apr 16, 2025 am 12:14 AM

Python在自动化、脚本编写和任务管理中表现出色。1)自动化:通过标准库如os、shutil实现文件备份。2)脚本编写:使用psutil库监控系统资源。3)任务管理:利用schedule库调度任务。Python的易用性和丰富库支持使其在这些领域中成为首选工具。

学习Python:2小时的每日学习是否足够? 学习Python:2小时的每日学习是否足够? Apr 18, 2025 am 12:22 AM

每天学习Python两个小时是否足够?这取决于你的目标和学习方法。1)制定清晰的学习计划,2)选择合适的学习资源和方法,3)动手实践和复习巩固,可以在这段时间内逐步掌握Python的基本知识和高级功能。

See all articles