flask部署深度学习模型

作为著名Python web框架之一的Flask,具有简单轻量、灵活、扩展丰富且上手难度低的特点,因此成为了机器学习和深度学习模型上线跑定时任务,提供API的首选框架。

众所周知,Flask默认不支持非阻塞IO的,当请求A还未完成时候,请求B需要等待请求A完成后才能被处理,所以效率非常低。但是线上任务通常需要异步、高并发等需求,本文总结一些在日常使用过程中所常用的技巧。

一、前沿

异步和多线程有什么区别?其实,异步是目的,而多线程是实现这个目的的方法。异步是说,A发起一个操作后(一般都是比较耗时的操作,如果不耗时的操作就没有必要异步了),可以继续自顾自的处理它自己的事儿,不用干等着这个耗时操作返回。

实现异步可以采用多线程技术或则交给另外的进程来处理,详解常见这里。

二、实现方法

  • Flask启动自带方法
  • 采用gunicorn部署

    1、Flask中自带方法实现

    run.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018-12-01 16:37
# @Author  : mokundong
from flask import Flask
import socket
from time import sleep  

myhost = socket.gethostbyname(socket.gethostname())
app = Flask(__name__)  

@app.route('/job1')
def some_long_task1():
    print("Task #1 started!")
    sleep(10)
    print("Task #1 is done!")  

@app.route('/job2')
def some_long_task2(arg1, arg2):
    print("Task #2 started with args: %s %s!" % (arg1, arg2))
    sleep(5)
    print("Task #2 is done!")  

if __name__ == '__main__':
    app.run(host=myhost,port=5000,threaded=True)

app.run(host=xxx,port=xx,threaded=True)
中threaded开启后则不需要等队列。

2、gunicorn部署

Gunicorn 是一个高效的Python WSGI Server,通常用它来运行 wsgi application 或者 wsgi framework(如Django,Paster,Flask),地位相当于Java中的Tomcat。gunicorn 会启动一组 worker进程,所有worker进程公用一组listener,在每个worker中为每个listener建立一个wsgi server。每当有HTTP链接到来时,wsgi server创建一个协程来处理该链接,协程处理该链接的时候,先初始化WSGI环境,然后调用用户提供的app对象去处理HTTP请求。
关于gunicorn的详细说明,可以参考这里。

使用命令行启动gunicorn有两种方式获取配置项,一种是在命令行配置,一种是在配置文件中获取。

run.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018-12-01 17:00
# @Author  : mokundong
from flask import Flask
from time import sleep  

app = Flask(__name__)  

@app.route('/job1')
def some_long_task1():
    print("Task #1 started!")
    sleep(10)
    print("Task #1 is done!")  

@app.route('/job2')
def some_long_task2(arg1, arg2):
    print("Task #2 started with args: %s %s!" % (arg1, arg2))
    sleep(5)
    print("Task #2 is done!")  

if __name__ == '__main__':
    app.run()

命令行配置

gunicorn --workers=4 --bind=127.0.0.1:8000 run:app

更多配置见官网

配置文件获取配置

gunicorn_config.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018-12-01 17:10
# @Author  : mokundong
import os
import socket
import multiprocessing
import gevent.monkey

gevent.monkey.patch_all()
myhost = socket.gethostbyname(socket.gethostname())  

debug = False
loglevel = 'info'
hosts = get_host_ip()
bind = hosts+":5000"
timeout = 30      #超时

pidfile = "log/gunicorn.pid"
accesslog = "log/access.log"
errorlog = "log/debug.log"

daemon = True #意味着开启后台运行,默认为False
workers = 4 # 启动的进程数
threads = 2 #指定每个进程开启的线程数
worker_class = 'gevent' #默认为sync模式,也可使用gevent模式。
x_forwarded_for_header = 'X-FORWARDED-FOR'

启动命令如下

gunicorn -c gunicorn_config.py run:app

三、补充

1、关于线程的补充

在工作中我还遇到一种情况,当一个请求过来后,我需要两种回应,一个是及时返回app运行结果,第二个响应是保存数据到日志或者数据库。往往我们在写数据的过程中会花销一定的时间,导致结果返回会有所延迟,因此我们需要用两个线程处理这两个任务,那么我们如下处理。

run.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018-12-01 17:20
# @Author  : mokundong
from flask import Flask,request
from time import sleep
from concurrent.futures import ThreadPoolExecutor
executor = ThreadPoolExecutor(2)
app = Flask(__name__)

@app.route('/job')
def run_jobs():
    executor.submit(some_long_task1)
    executor.submit(some_long_task2, 'hello', 123)
    return 'Two jobs was launched in background!'
def some_long_task1():
    print("Task #1 started!")
    sleep(10)
    print("Task #1 is done!")

def some_long_task2(arg1, arg2):
    print("Task #2 started with args: %s %s!" % (arg1, arg2))
    sleep(5)
    print("Task #2 is done!")

if __name__ == '__main__':
    app.run()

2、关于获取IP的补充

上述代码中通过获取hostname,然后再通过hostname反查处机器的IP。这个方法是不推荐的。因为很多的机器没有规范这个hostname的设置。
另外就是有些服务器会在 /etc/hosts 中添加本机的hostname的地址,这个做法也不是不可以,但是如果设置成了 127.0.0.1,那么获取出来的IP就都是这个地址了。
这里给出一种优雅的方式获取IP,利用 UDP 协议来实现的,生成一个UDP包,把自己的 IP 放如到 UDP 协议头中,然后从UDP包中获取本机的IP。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018-12-01 17:30
# @Author  : mokundong
# 可以封装成函数,方便 Python 的程序调用
import socket

def get_host_ip():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(('8.8.8.8', 80))
        ip = s.getsockname()[0]
    finally:
        s.close()

    return ip

总结

当然推荐使用gunicorn部署多线程,Flask自带的,emmmm,测试玩儿玩儿吧。
在写作过程中才发现自己知识漏洞不是一般多,共勉!

flask部署深度学习模型的更多相关文章

  1. PyTorch如何构建深度学习模型?

    简介 每过一段时间,就会有一个深度学习库被开发,这些深度学习库往往可以改变深度学习领域的景观.Pytorch就是这样一个库. 在过去的一段时间里,我研究了Pytorch,我惊叹于它的操作简易.Pyto ...

  2. Apple的Core ML3简介——为iPhone构建深度学习模型(附代码)

    概述 Apple的Core ML 3是一个为开发人员和程序员设计的工具,帮助程序员进入人工智能生态 你可以使用Core ML 3为iPhone构建机器学习和深度学习模型 在本文中,我们将为iPhone ...

  3. 用 Java 训练深度学习模型,原来可以这么简单!

    本文适合有 Java 基础的人群 作者:DJL-Keerthan&Lanking HelloGitHub 推出的<讲解开源项目> 系列.这一期是由亚马逊工程师:Keerthan V ...

  4. CUDA上深度学习模型量化的自动化优化

    CUDA上深度学习模型量化的自动化优化 深度学习已成功应用于各种任务.在诸如自动驾驶汽车推理之类的实时场景中,模型的推理速度至关重要.网络量化是加速深度学习模型的有效方法.在量化模型中,数据和模型参数 ...

  5. 用TVM在硬件平台上部署深度学习工作负载的端到端 IR 堆栈

    用TVM在硬件平台上部署深度学习工作负载的端到端 IR 堆栈 深度学习已变得无处不在,不可或缺.这场革命的一部分是由可扩展的深度学习系统推动的,如滕索弗洛.MXNet.咖啡和皮托奇.大多数现有系统针对 ...

  6. CUDA上的量化深度学习模型的自动化优化

    CUDA上的量化深度学习模型的自动化优化 深度学习已成功应用于各种任务.在诸如自动驾驶汽车推理之类的实时场景中,模型的推理速度至关重要.网络量化是加速深度学习模型的有效方法.在量化模型中,数据和模型参 ...

  7. TVM将深度学习模型编译为WebGL

    使用TVM将深度学习模型编译为WebGL TVM带有全新的OpenGL / WebGL后端! OpenGL / WebGL后端 TVM已经瞄准了涵盖各种平台的大量后端:CPU,GPU,移动设备等.这次 ...

  8. AI佳作解读系列(一)——深度学习模型训练痛点及解决方法

    1 模型训练基本步骤 进入了AI领域,学习了手写字识别等几个demo后,就会发现深度学习模型训练是十分关键和有挑战性的.选定了网络结构后,深度学习训练过程基本大同小异,一般分为如下几个步骤 定义算法公 ...

  9. 『高性能模型』Roofline Model与深度学习模型的性能分析

    转载自知乎:Roofline Model与深度学习模型的性能分析 在真实世界中,任何模型(例如 VGG / MobileNet 等)都必须依赖于具体的计算平台(例如CPU / GPU / ASIC 等 ...

随机推荐

  1. java DOM 操作xml

    1 代码如下: package dom.pasing; import java.io.IOException; import java.io.StringWriter; import javax.xm ...

  2. vue调用兄弟组件的方法使用vueBus调用$emit、$on(只需触发方法即可,不需要考虑传值或参数的问题)

    触发方: vueBus.$emit('queryAll') 被触发方: created() { vueBus.$on('queryAll', () => { this.getList() // ...

  3. linux 位操作

    atomic_t 类型在进行整数算术时是不错的. 但是, 它无法工作的好, 当你需要以原子方 式操作单个位时. 为此, 内核提供了一套函数来原子地修改或测试单个位. 因为整个操作 在单步内发生, 没有 ...

  4. JAVA JVM记录

    串行处理器: 适用情况:数据量比较小(100M左右):单处理器下并且对响应时间无要求的应用. 缺点:只能用于小型应用 并行处理器: 适用情况:“对吞吐量有高要求”,多CPU.对应用响应时间无要求的中. ...

  5. C# 标准性能测试高级用法

    本文告诉大家如何在项目使用性能测试测试自己写的方法 在 C# 标准性能测试 已经告诉大家如何使用 BenchmarkDotNet 测试性能,本文会告诉大家高级的用法. 建议是创建一个控制台项目用来做性 ...

  6. nginx负载均衡的几种模式

    nginx 的 upstream目前支持 4 种方式的分配 ).轮询(默认) 每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除. ).weight 指定轮询几率,we ...

  7. java环境所遇问题

    在javac能运行通过并且生成了.class文件但是java文件在运行时通不过出现上面图片情况,试了一上午发现我的和别人好像不一样,下面展示我的情况, 之前用户变量那里新建了一个classpath,不 ...

  8. git之分支

    分支相互之间互不干扰 1.小乌龟创建分支,切换/检出   创建后直接切换到该分支,另一个需要再切换一下. 2.点击这个可以看到所有的分支,进行删除操作. 3.在fen1,fen2分别进行操作更新,互不 ...

  9. easyUI demo2

    图片:               代码: jsp <%@ page language="java" import="java.util.*" pageE ...

  10. golang实现依赖注入

    golang实现依赖注入 依赖注入是软件工程中经常使用到的一种技术,它提供了一种控制反转的机制,把控制权利交给了调用方.调用方来决定使用哪些参数,哪些对象来进行具体的业务逻辑. 它有几个好处: 1 它 ...