不支持协程异步
并发。也就是说即使使用了协程异步编程,但如果使用flask开发的app接口,外部并发
请求时,flask
还是会把这些 "已经异步编程的接口"
当成 同步接口
执行。但flask并不支持异步编程,推荐支持异步编程的 Web 框架,如 aiohttp 或 fastapi。
本质: 多线程并发。虽然宏观上看好像是协程的并发(单线程的并发)。
虽然asynic await关键字旨在实现同一线程里的并发,但flask并不原生支持这一特性(“不支持”不是说“不能调用”)。
所以,同一时间、同一线程、多个请求并发请求时,不管有无asynic await关键字修饰请求接口,flask都是一个一个顺序的、同步处理他们,而不是并发处理。
这里的装饰器实现的功能:
在 Making Flask async and Quart sync, Quart 的作者 PG Jones 给出了一个 Flask 异步化的代码,route 方法可加上 async 关键字
和 @run_async 装饰
当并发请求时,给
每个请求
开创一个线程
单独的处理,这样并发的请求就被放到了多线程里,从宏观上看就是并发了,这样也不会因为某个接口请求阻塞而导致其他接口也无法响应的问题。
但这种异步装饰器
,只是宏观上的“像”协程并发(协程:单线程下的并发),其实是多线程并发
。
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
'''
@Project :hippo-ai-py
@Author :cf
@Date :2024/4/2
@Desc : api公用信息
'''
import asyncio
from concurrent.futures import Future, ThreadPoolExecutor
from functools import wraps
from flask import Flask, has_request_context, copy_current_request_context
def run_async(func):
'''
flask异步视图装饰器。
Args:
func: 调用的方法
Returns:
'''
@wraps(func)
def _wrapper(*args, **kwargs):
call_result = Future()
def _run():
loop = asyncio.new_event_loop()
try:
result = loop.run_until_complete(func(*args, **kwargs))
except Exception as error:
call_result.set_exception(error)
else:
call_result.set_result(result)
finally:
loop.close()
loop_executor = ThreadPoolExecutor(max_workers=1)
if has_request_context():
_run = copy_current_request_context(_run)
loop_future = loop_executor.submit(_run)
loop_future.result()
return call_result.result()
return _wrapper
app = Flask(__name__)
async def fetch(url):
print(f"{threading.current_thread().name}:{url}")
return requests.get(url).text
async def main(t):
await asyncio.sleep(t)
tasks = [fetch(url) for url in ["https://baidu.com", "https://bing.com", "https://yanbin.blog"]]
return await asyncio.gather(*tasks)
@app.route("/")
@run_async
async def index():
time1 = time.time()
responses = await main(3)
time2 = time.time()
print(f'{threading.current_thread().name}--3:response sizes: {[len(res) for res in responses]},耗时{time2 - time1}s\n')
return responses
if __name__ == "__main__":
# app.run(debug=False, use_reloader=False,threaded=False)
app.run(debug=False, use_reloader=False)
本质: 多线程、多进程的并发。
本质: 协程(单线程)并发。
待续。。。。。。。。。