栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

fastapi 接口阻塞问题处理

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

fastapi 接口阻塞问题处理

fastapi 接口阻塞问题处理
  • 背景
  • 问题复现
  • 解决方法1
  • 解决方法2
  • 总结

背景

在使用fastapi框架开发时,遇到一个坑,在请求某个耗时的接口时,再请求其他接口,发现请求都被阻塞卡住了,经过排查问题,发现是async使用不当导致的

问题复现

这里写了一个小demo文件,里面有耗时函数work 和 两个接口 /test1、 /test2

def work(s):
    print("work start work")
    time.sleep(s)
    print("work end work")


@api.get("/test1")
async def test1():
    print("func: test1")
    return "test1"


@api.get("/test2")
async def test2():
    a = int(time.time())
    print(f"start: {a}")
    work(8)
    b = int(time.time())
    print(f"start: {b-a}")
    return f"test2耗时:{b-a}"

使用如下测试脚本请求接口测试

import time
import requests
from threading import Thread

def task1():
    a = int(time.time())
    requests.get(url="http://127.0.0.1:8000/test/test1")
    b = int(time.time())
    print(f"test1耗时{b - a}")


def task2():
    a = int(time.time())
    requests.get(url="http://127.0.0.1:8000/test/test2")
    b = int(time.time())
    print(f"test2耗时{b - a}")


Thread(target=task1).start()
Thread(target=task2).start()

运行测试脚本发现,/test1被阻塞了,等/test2处理完之后,/test1 才返回结果
执行顺序如下

test2--start: 1652973708
work start work
work end work
test2--end: 1652973716
test1--执行
INFO:     127.0.0.1:63965 - "GET /test/test2 HTTP/1.1" 200 OK
INFO:     127.0.0.1:63966 - "GET /test/test1 HTTP/1.1" 200 OK

测试脚本

test1耗时8
test2耗时8

Process finished with exit code 0

可以看到,/test1在/test2执行完之后才执行,/test1请求同样耗时8秒

解决方法1

直接删除掉 /test2 的 async
改为如下:

@api.get("/test2")
def test2():
    a = int(time.time())
    print(f"test2--start: {a}")
    work(8)
    b = int(time.time())
    print(f"test2--end: {b}")
    return f"test2耗时:{b-a}"

此时运行测试脚本,执行顺序如下

test1--执行
test2--start: 1652973918
work start work
INFO:     127.0.0.1:64024 - "GET /test/test1 HTTP/1.1" 200 OK
work end work
test2--end: 1652973926
INFO:     127.0.0.1:64023 - "GET /test/test2 HTTP/1.1" 200 OK

耗时

test1耗时0
test2耗时8

Process finished with exit code 0

解决方法2

利用asyncio获取当前的event loop。
然后将耗时函数work放到一个event loop中去运行
如图

@api.get("/test2")
async def test2():
    a = int(time.time())
    print(f"test2--start: {a}")
    loop = asyncio.get_event_loop()
    await loop.run_in_executor(None, work, 8)
    b = int(time.time())
    print(f"test2--end: {b}")
    return f"test2耗时:{b-a}"

执行顺序如下

test2--start: 1652974163
work start work
test1--执行
INFO:     127.0.0.1:64094 - "GET /test/test1 HTTP/1.1" 200 OK
work end work
test2--end: 1652974171
INFO:     127.0.0.1:64093 - "GET /test/test2 HTTP/1.1" 200 OK

耗时

test1耗时0
test2耗时8

Process finished with exit code 0
总结

如果定义了async函数,函数体却是同步的调用,将导致函数执行过程变成串行,所以在 async函数里如果有io等阻塞的地方一定要使用 await 将程序挂起。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/917650.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号