django:restframework定义异步接口daphne部署

1. adrf库

链接: pypi

基本介绍

  1. 介绍
    Async support for Django REST framework
    对 Django REST 框架的异步支持
  2. 要求
    Requirements
    Python 3.8+
    Django 4.1+

2. django

2.1. django3.2(此版本只能普通函数实现异步,连接数据库操作不支持异步)

当前环境不满足条件,所以不能直接使用adrf

2.1.1. 获取代码

  1. 新建python虚拟环境(为了获取adrf中的代码,避免把项目环境中的django更新)
  2. 执行pip install adrf==0.1.3
  3. 进入adrf的packages,目录如下:
    adrf
    不包含async_viewsets.py,后续会提到。
  4. 在当前django3.2项目的apps目录下新建adrf文件夹,将另外6个文件复制进去

2.1.2. 编写逻辑

1. async_viewsets.py

文件位置:apps/adrf/async_viewsets.py
在apps/adrf/viewsets.py中已经实现了异步viewsets,但是每次需要继承多个父类比较费劲,直接继承好得了。

from apps.adrf.viewsets import ViewSet as AsyncViewSet
from rest_framework import generics, mixins, views


class AsyncGenericViewSet(AsyncViewSet, generics.GenericAPIView):
    # 以后凡是用GenericViewSet的地方都可以用此类替换
    pass

2. serializer

文件位置:apps/app1/serializers.py

from apps.adrf.serializers import Serializer as AsyncSerializer


class QASerializer(AsyncSerializer):
    """知识问答历史记录格式"""
    role = serializers.CharField(required=True, max_length=32, allow_null=False, allow_blank=False,
                                 help_text='角色')
    content = serializers.CharField(required=True, max_length=1024, allow_null=False, allow_blank=False,
                                    help_text='内容')

    class Meta:
        fields = ['role', 'content']
3. views.py

文件位置:apps/app1/views.py

import asyncio
from asgiref.sync import sync_to_async
from apps.adrf.async_viewsets import AsyncGenericViewSet  # 2.1中自己写的


class DataKnowledgeViewSet(mixins.RetrieveModelMixin, AsyncGenericViewSet):
    queryset = DataKnowledge.objects.all()
    serializer_class = DataKnowledgeModelSerializer

    def get_serializer_class(self):
        if self.action in ['qa1']:
            self.serializer_class = QASerializer
        return self.serializer_class

	@swagger_auto_schema(operation_description="知识问答",
                         operation_summary='知识问答',
                         tags=['知识'],
                         responses={**SWAGGER_RESPONSE_MESSAGE, 200: 'ok'})
    @action(methods=['POST'], detail=False, url_path='qa1', url_name='qa1')
    async def qa1(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data, many=True)
        serializer.is_valid(raise_exception=True)
        data = await serializer.adata  # data = serializer.data 响应时间差不多
        await asyncio.sleep(2)
        return Response(data)
    
    @swagger_auto_schema(operation_description="知识问答",
                         operation_summary='知识问答',
                         tags=['知识'],
                         responses={**SWAGGER_RESPONSE_MESSAGE, 200: 'ok'})
    @action(methods=['POST'], detail=False, url_path='qa2', url_name='qa2')
    async def qa2(self, request, *args, **kwargs):
    	msg = random.randint(0,99)
        await asyncio.sleep(2)
        return Response(msg)
  
    @swagger_auto_schema(operation_description="知识问答",
                         operation_summary='知识问答',
                         tags=['知识'],
                         responses={**SWAGGER_RESPONSE_MESSAGE, 200: 'ok'})
    @action(methods=['POST'], detail=False, url_path='qa3', url_name='qa3')
    def qa3(self, request, *args, **kwargs):
    	msg = random.randint(0, 99)
        return Response(msg)

2.1.3. 测试

不能用requests测不出来。。

import time
import asyncio
import aiohttp
import json


async def fetch(session):
    payload = json.dumps([
        {
            "role": "user",
            "content": "dsm出现了红色错误"
        }
    ])
    headers = {
        'Content-Type': 'application/json'
    }
    url1 = "http://127.0.0.1:8001/cn/api/data-knowledge/qa1/"
    url2 = "http://127.0.0.1:8001/cn/api/data-knowledge/qa2/"
    url3 = "http://127.0.0.1:8001/cn/api/data-knowledge/qa3/"
    async with session.post(url1, data=payload, headers=headers) as response:
        return await response.text()


async def xxx():
    async with aiohttp.ClientSession() as session:
        html = await fetch(session)
        print(html)


async def main(req_count=10):
    tasks = []
    for i in range(0, req_count):
        task = asyncio.create_task(xxx())
        tasks.append(task)
    await asyncio.wait(tasks)

# 运行异步任务
x1 = time.time()
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
x2 = time.time()
print(x2 - x1)

###结果
# url1
{"message":"OK","code":200,"results":[{"role":"user","content":"dsm出现了红色错误"}]}
{"message":"OK","code":200,"results":[{"role":"user","content":"dsm出现了红色错误"}]}
{"message":"OK","code":200,"results":[{"role":"user","content":"dsm出现了红色错误"}]}
{"message":"OK","code":200,"results":[{"role":"user","content":"dsm出现了红色错误"}]}
{"message":"OK","code":200,"results":[{"role":"user","content":"dsm出现了红色错误"}]}
{"message":"OK","code":200,"results":[{"role":"user","content":"dsm出现了红色错误"}]}
{"message":"OK","code":200,"results":[{"role":"user","content":"dsm出现了红色错误"}]}
{"message":"OK","code":200,"results":[{"role":"user","content":"dsm出现了红色错误"}]}
{"message":"OK","code":200,"results":[{"role":"user","content":"dsm出现了红色错误"}]}
{"message":"OK","code":200,"results":[{"role":"user","content":"dsm出现了红色错误"}]}
2.2377092838287354

# url2
{"message":"OK","code":200,"results":92}
{"message":"OK","code":200,"results":95}
{"message":"OK","code":200,"results":55}
{"message":"OK","code":200,"results":64}
{"message":"OK","code":200,"results":13}
{"message":"OK","code":200,"results":81}
{"message":"OK","code":200,"results":83}
{"message":"OK","code":200,"results":28}
{"message":"OK","code":200,"results":2}
{"message":"OK","code":200,"results":8}
2.2307043075561523

# url3同步函数正常返回

2.2 django4.2及以上

连接数据库自带异步???adrf存在的意义?

普通函数还是可以通过adrf进行异步返回

async def qa2(self, request, *args, **kwargs):
	msg = random.randint(0,99)
    await asyncio.sleep(2)
    return Response(msg)

2.2.1 daphne启动 同步函数

ModelSerializer
def retrieve(self, request, *args, **kwargs):
     return super().retrieve(request, *args, **kwargs)

单个请求:0.8s
在这里插入图片描述
50个请求:2.4s
在这里插入图片描述

2.2.2 runserver启动同步函数

ModelSerializer
def retrieve(self, request, *args, **kwargs):
     return super().retrieve(request, *args, **kwargs)

1个请求:0.8s
50个请求:1.8s

2.2.3 dephne启动异步函数

AsyncModelSerializer
async def retrieve(self, request, *args, **kwargs):
    instance = await self.aget_object()
    serializer = self.get_serializer(instance)
    data = await serializer.adata
    return Response(data)

单个请求:0.8s
50个请求:2.4s

3. 启动项目

runserver开发阶段支持异步,如果想同步那么把下面INSTALLED_APPS 中的daphne注释

3.1. daphne

安装:pip install daphne

配置:settings.py

INSTALLED_APPS = [
     ...
     'daphne',  # 需要靠前位置
     ...
]
...
ASYNC_MODE = 'django'  # 不知道啥用
ASGI_APPLICATION = 'service_brain_model.asgi.application'

启动:daphne service_brain_model.asgi:application -h 0.0.0.0 -p 8001

3.2. pycharm配置方式(windows)

daphne

如有问题欢迎指正

  • 15
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值