2周刷完100道前端优质面试真题

339 阅读4分钟

2周刷完100道前端优质面试真题

flask中运用协程,经过gunicorn或uwsgi搭建web效劳时遇到的坑

我需求经过flask搭一个深度学习的接口,由于深度学习耗时很长,flask的http效劳是单向被动通讯,(客户端恳求,效劳器端响应)。客户端发来一个get恳求,http效劳在等候深度学习模型响应,假如数据量很大,衔接一定会超时。

需求就变成,我需求写一个flask接口,返回response的同时,还需求运转深度学习模型,这里运用了多线程,其中我还用协程调一个内部的查询api,部署时用docker+uwsgi。变成了docker+uwsgi+flask+threading+gevent。

问题就出在了gevent和uwsgi上,昨天坑了我一天并且我还没有找到缘由。

今天我就改成docker+gunicorn+flask+threading+gevent。胜利部署之后,我就开端排查发现是gevent+uwsgi出的问题。下面做了点实验考证我的想法,假如实验局部不想看,倡议拉到最后看结论局部。

PS . uwsgi 和 gunicorn 在windows装置根本不胜利,倡议运用docker或者linux系统,不然,努力半天就像什么都没干一样。

app = Flask(__name__)

# 模仿恳求

def get_url(num):

time.sleep(num)

print(f"cost:{num}s")

def gevent_get(msg):

print(msg)

s=perf_counter()

pool=Pool(5)

threads=[pool.spawn(get_url,num) for num in [1,2,3,2,1,2,3,4,4,5]]

gevent.joinall(threads

@app.route("/test", methods=["post","get"])

def test():

t = threading.Thread(target=gevent_get, args=("开端",))

t.start()

return jsonify({"code": 500,"msg": "success"})

if __name__ == '__main__':

app.run(debug=True)

复制代码

# test.py

import requests

URL="http://192.168.160.237:8000/test"

response=requests.get(URL).json()

print(response)

复制代码

# uwsgi.ini

[uwsgi]

# app是run.py里面的Flask对象

module = main:app

# 对外提供 http 效劳的端口

http = :8000

#指定工作进程

processes = 4

#主进程

master = true

#每个工作进程有2个线程

threads = 2

#指的后台启动 日志输出的中央

daemonize = uwsgi.log

#保管主进程的进程号

pidfile = uwsgi.pid

复制代码

docker build创立之后,经过uwsgi启动

uwsgi uwsgi.ini

假如按正常逻辑,输出应该是下面的结果

开端

[pid: 632|app: 0|req: 1/1] 172.17.0.1 () {32 vars in 386 bytes} [Tue Feb 15 05:28:25 2022] GET /test => generated 29 bytes in 4 msecs (HTTP/1.1 200) 2 headers in 71 bytes (3 switches on core 0)

sleep:1s

sleep:1s

sleep:2s

sleep:2s

sleep:3s

sleep:2s

sleep:3s

sleep:4s

sleep:4s

sleep:5s

破费时间8.007732099999885

复制代码

但是实践输出的结果,到“开端”就卡住了。也就是gevent没有用。

开端

[pid: 632|app: 0|req: 1/1] 172.17.0.1 () {32 vars in 386 bytes} [Tue Feb 15 05:28:25 2022] GET /test => generated 29 bytes in 4 msecs (HTTP/1.1 200) 2 headers in 71 bytes (3 switches on core 0)

复制代码

我昨天弄了一天也没处理,由于上面的代码是我今天想通之后简化的,开发代码逻辑要复杂更多。后面我就生气了,我就改成gunicorn。结果还是出问题了。

# 我就改成gunicorn.py

# 绑定的ip与端口

bind = "0.0.0.0:8000"

# 进程数

workers = 4

# 指定每个进程开启的线程数

# threads = 2

# 工作形式

worker_class = 'gthread'

# 处置恳求的工作线程数,运用指定数量的线程运转每个worker。为正整数,默许为1。

# worker_connections = 2000

# 设置pid文件的文件名,假如不设置将不会创立pid文件

pidfile = './gunicorn.pid'

# 要写入错误日志的文件目录。

errorlog = './log/gunicorn.error.log'

# 要写入的访问日志目录

accesslog = './log/gunicorn.access.log'

复制代码

正常输出应该是这样:

gunicorn -c gunicorn.py main:app

开端

sleep:1s

sleep:1s

sleep:2s

sleep:2s

sleep:3s

sleep:2s

sleep:3s

sleep:4s

sleep:4s

sleep:5s

复制代码

但这里通要还是会卡住

gunicorn -c gunicorn.py main:app

开端

复制代码

经过我多轮百度,翻看博客,发现gunicorn worker_class = 'gthread'有玄机。

我修正成worker_class = 'gevent'之后就一切正常了。默许的"sync"也是正常的

于是,我心血来潮想着是不是uwsgi也是和gevent有抵触。百度了一下,果真在uwsgi中运用协程要加一句话。

uwsgi uwsgi.ini --gevent 100 --gevent-early-monkey-patch

期间我还做了一下,gunicorn worker_class和uwsgi会不会对多线程有影响,结果是没有什么影响。

# main.py

import threading

from flask import Flask, request, jsonify

import time

app = Flask(__name__)

def get_url(num):

for i in range(num):

time.sleep(0.5)

print(i)

@app.route("/test", methods=["post","get"])

def test():

num=10

t = threading.Thread(target=get_url, args=(num,))

t.start()

return jsonify({"code": 500,"msg": "success"})

if __name__ == '__main__':

app.run(debug=True)

复制代码

补充

后续还会研讨一下,把上面的gevent交换成thread在做相同实验。

结论

在运用gevent+flask+uwsgi,配置启动

uwsgi uwsgi.ini --gevent 100 --gevent-early-monkey-patch

hi在运用gevent+flask+gunicorn,配置中形式worker_class = 'gevent'

gunicorn -c gunicorn.py main:app

      download