警告:乱用async导致灾难
背景
研发过程中,测试同事反馈,调用XX接口的时候其他的接口全部没法调用了,都被阻塞住了。
我当时认为,机器太挫了,有其他任务在机器上运行,请求无法处理。但,很快我就被打脸。
这里用一个DEMO来展示,只包含了三个文件
第一个文件 fastApiServer,这个文件里面定义了两个API,并启动了服务器
import xmlrpc.client
import uvicorn
from datetime import datetime
from fastapi import FastAPI
app = FastAPI()
@app.get("/root1")
async def root1():
print("1111", datetime.now())
# 调用RPC
url = 'http://{}:{}'.format("127.0.0.1", 1081)
client = xmlrpc.client.ServerProxy(url)
res = client.test1()
if res is not None:
print(res)
# 调用RPC结束
print("2222", datetime.now())
return {"message": "Hello World"}
@app.get("/root2")
async def root2():
print("3333", datetime.now())
# 调用RPC
url = 'http://{}:{}'.format("127.0.0.1", 1081)
client = xmlrpc.client.ServerProxy(url)
res = client.test2()
if res is not None:
print(res)
# 调用RPC结束
print("4444", datetime.now())
return {"message": "Hello World"}
uvicorn.run(app=app, host="0.0.0.0", port=1080, timeout_keep_alive=1200)
第二个文件rpcServer.py
import time
from socketserver import ThreadingMixIn
from xmlrpc.server import SimpleXMLRPCServer
class ThreadXMLRPCServer(ThreadingMixIn, SimpleXMLRPCServer):
name = "xml-server"
def test1():
print("test1()")
time.sleep(10)
status = "1"
return status
def test2():
print("test2()")
status = "2"
return status
server = ThreadXMLRPCServer(('0.0.0.0', 1081))
server.register_function(test1, "test1")
server.register_function(test2, "test2")
server.serve_forever()
第三个文件 test.py 测试文件,先后发送两个请求
import time
from threading import Thread
import requests
def k1():
requests.get(url="http://127.0.0.1:1080/root1")
def k2():
requests.get(url="http://127.0.0.1:1080/root2")
Thread(target=k1).start()
time.sleep(1)
Thread(target=k2).start()
启动服务
跑测试
我震惊发现,两个先后间隔1秒到达的请求,竟然需要等待第一个请求结束之后,才会去处理第二个请求
问题原因
如果你定义了async函数,函数体却是同步的调用,将导致函数执行过程变成串行。
解决方案
方法一 直接删除async
import xmlrpc.client
import uvicorn
from datetime import datetime
from fastapi import FastAPI
app = FastAPI()
@app.get("/root1")
def root1():
print("1111", datetime.now())
# 调用RPC
url = 'http://{}:{}'.format("127.0.0.1", 1081)
client = xmlrpc.client.ServerProxy(url)
res = client.test1()
if res is not None:
print(res)
# 调用RPC结束
print("2222", datetime.now())
return {"message": "Hello World"}
@app.get("/root2")
def root2():
print("3333", datetime.now())
# 调用RPC
url = 'http://{}:{}'.format("127.0.0.1", 1081)
client = xmlrpc.client.ServerProxy(url)
res = client.test2()
if res is not None:
print(res)
# 调用RPC结束
print("4444", datetime.now())
return {"message": "Hello World"}
uvicorn.run(app=app, host="0.0.0.0", port=1080, timeout_keep_alive=1200)
修改后,再次运行测试脚本
结果和预期一致。
结论
在不了解所调用函数是否支持await的情况下,不使用async,使用普通函数即可