Python编写异步sanic接口

一、背景

最近使用sanic框架开发一个Python后台程序,涉及多个接口开发,且有的接口需要运行耗时较长的任务,不得不使用异步。
看了很多关于异步编程的博客,比如廖雪峰大哥的一篇Python 异步编程入门,亲自实践发现,不是随便加个await/async关键字就可以实现异步,支持异步的库本来就不多,如果业务复杂基本找不到合适的库支持,还好找了好久,终于有了解决办法。

二、如何实现异步sanic接口

下面使用一个小型的sanic框架搭建的服务来说明

1、代码目录结构及说明

  • |— bp.py 接口蓝本,定义了一个可供外部调用的GET接口
  • |— interface.py 接口具体实现
  • |— app.py 服务启动入口

2、bp.py

通过blueprint定义接口,调用后及时返回响应信息,异步后台运行InterfaceImpl.df方法,无需等待。

# !/usr/bin/env python3
# -*- coding    : utf-8 -*-
# @Time         : 2020/11/9 16:27
# @Author       : Attaboy
# @Email        : slum2183@163.com
# @File         : bp.py
# @Software     : PyCharm

from sanic import response
from sanic import Blueprint
from interface import InterfaceImpl

# strict_slashes 控制请求的URL严格匹配
test_bp = Blueprint('test_bp', strict_slashes=True)


# 定义接口
@test_bp.route('/df', methods=['GET', 'OPTIONS'])
async def df(request):
    await InterfaceImpl.df(request)
    return response.json({"msg": "cmd running success"})

3、interface.py

上面定义的接口具体实现,先获取事件循环,再让封装好的函数os.system运行在指定的线程里,这里使用ping程序模拟耗时任务,后面有测试结果。

# !/usr/bin/env python3
# -*- coding    : utf-8 -*-
# @Time         : 2021/1/29 16:57
# @Author       : Attaboy
# @Email        : slum2183@163.com
# @File         : interface.py
# @Software     : PyCharm

import asyncio
import os
import uvloop

# uvloop是asyncio中的事件循环的替代方案,替换后可以使得asyncio性能提高。
# 事实上,uvloop要比nodejs、gevent等其他python异步框架至少要快2倍,性能可以比肩Go语言。
asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())


class InterfaceImpl():

    # 创建AI测评任务的接口
    @staticmethod
    async def df(request):
        loop = asyncio.get_event_loop()
        # 另起一个非阻塞的线程运行任务,核心代码,花了两天查阅资料
        loop.run_in_executor(None, os.system, "ping -c 5 127.1")

4、app.py

服务启动文件,监听在本地8080端口

# !/usr/bin/env python3
# -*- coding    : utf-8 -*-
# @Time         : 2020/11/6 15:57
# @Author       : Attaboy
# @Email        : slum2183@163.com
# @File         : app.py
# @Software     : PyCharm

import os
import sys

from sanic import Sanic
from bp import test_bp


# 添加sys.path路径
sys.path.append(os.getcwd())

app = Sanic(__name__)
app.blueprint(test_bp)


def entry_point():
    app.run(host="127.0.0.1", port=8080, workers=2, debug=False)


if __name__ == '__main__':
    entry_point()

三、测试

Ubuntu里启动该服务

tom@ros-ubuntu1804:~/project/python/test$ python app.py 
[2021-02-19 22:26:46 +0800] [959] [INFO] Goin' Fast @ http://127.0.0.1:8080
[2021-02-19 22:26:46 +0800] [1004] [INFO] Starting worker [1004]
[2021-02-19 22:26:46 +0800] [1006] [INFO] Starting worker [1006]

Ubuntu本地curl接口三次,三次都立即返回响应信息,无阻塞。

tom@ros-ubuntu1804:~$ date ; for i in $(seq 3) ; do curl http://localhost:8080/df ; echo ; done ; date
Fri Feb 19 22:38:58 CST 2021
{"msg":"cmd running success"}
{"msg":"cmd running success"}
{"msg":"cmd running success"}
Fri Feb 19 22:38:58 CST 2021

查看服务控制台日志,耗时任务运行正常。

[2021-02-19 22:39:50 +0800] - (sanic.access)[INFO][127.0.0.1:38638]: GET http://localhost:8080/df  200 29
PING 127.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.019 ms
[2021-02-19 22:39:50 +0800] - (sanic.access)[INFO][127.0.0.1:38642]: GET http://localhost:8080/df  200 29
PING 127.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.009 ms
[2021-02-19 22:39:50 +0800] - (sanic.access)[INFO][127.0.0.1:38646]: GET http://localhost:8080/df  200 29
PING 127.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.010 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.034 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.023 ms
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.014 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.034 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.016 ms
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.010 ms
64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.034 ms
64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.017 ms
64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.009 ms
64 bytes from 127.0.0.1: icmp_seq=5 ttl=64 time=0.031 ms

--- 127.1 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4059ms
rtt min/avg/max/mdev = 0.019/0.030/0.034/0.007 ms
64 bytes from 127.0.0.1: icmp_seq=5 ttl=64 time=0.010 ms

--- 127.1 ping statistics ---
64 bytes from 127.0.0.1: icmp_seq=5 ttl=64 time=0.016 ms
5 packets transmitted, 5 received, 0% packet loss, time 4068ms

rtt min/avg/max/mdev = 0.009/0.010/0.014/0.004 ms
--- 127.1 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4080ms
rtt min/avg/max/mdev = 0.009/0.016/0.023/0.005 ms
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值