提升基于python的web服务并发性能

最近在做一个基于ws通信协议的实时语音识别项目,在测试并发性能的时候显存、内存、带宽这些资源都没有达到瓶颈,但是实时语音识别的响应时间已经很大了,下面讲一下我的处理方式。

问题:
测试并发性能的时候显存、内存、带宽这些资源都没有达到瓶颈,但是并发的路数却提不上去。

问题原因:
问题出在我的服务是跑在单个线程上的,虽然用了异步的处理方式,但由于python的GIL的限制,并不能做到真正的并行处理,导致并发路数提不上去。

解决方法:
一般有两种方式,多线程和多进程,打破GIL的限制,这里我使用的是多进程的方式。

import json
import torch
import websockets
import asyncio
import ssl
import time
import socket
from multiprocessing import Process, Manager
from infer_server_self_utils import *
from transcribe_fn import transcribe as zhuanlu
import warnings
import pdb
import resource
resource.setrlimit(resource.RLIMIT_NOFILE, (65535, 65535))  # 设置进程可以打开的最大文件数限制的

warnings.filterwarnings("ignore", category=FutureWarning)


async def hello(websocket, shared_pipeline):
    try:
        # 将共享的pipeline转移到cuda上
        shared_pipeline.device = torch.device("cuda")  # 进程之间共享模型必须是加载的cpu的模型,进程加载之后再放在cuda上
        shared_pipeline.model.to(torch.device("cuda")
            
        while True:
            audio_bytes = await websocket.recv()  # 接收数据
            if audio_bytes == 'null':  # 判断是否结束
                res_results = {"result": '', "status": 'true'}
                await websocket.send(str(res_results))
            else:
                text = shared_pipeline(audio_bytes)  # 转录接收的数据
                res_results = {"result": text['text'], "status": 'true'}
                await websocket.send(str(res_results))

    except websockets.exceptions.ConnectionClosedError as e:
        print(f"Connection closed unexpectedly: {e}")
    
    finally:
        # 连接关闭时,将模型移回CPU并释放显存
        shared_pipeline.model.to(torch.device("cpu"))
        torch.cuda.empty_cache()

def start_websocket_worker(shared_pipeline):
    # 创建一个套接字并设置SO_REUSEPORT选项,实现多进程
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
    sock.bind(('0.0.0.0', 30582))
    sock.listen(5)
    asyncio.set_event_loop(asyncio.new_event_loop())
    loop = asyncio.get_event_loop()

    async def accept_connection(websocket, path):
        await hello(websocket, shared_pipeline)

    start_server = websockets.serve(accept_connection, sock=sock)
    loop.run_until_complete(start_server)
    loop.run_forever()

if __name__ == '__main__':
    # 在多进程中使用torch
    torch.multiprocessing.set_start_method('spawn')
    
    # 构建共享模型管理器
    manager = Manager()
    pipeline, generate_kwargs = zhuanlu()  # zhuanlu()是我用来读取语音识别pipeline的一个函数
    shared_pipeline = manager.Namespace()
    shared_pipeline.pipeline= pipeline
        
    num_workers = 4  # 工作进程数,可以根据需求调整
    # 启动工作进程
    processes = []
    for _ in range(num_workers):
        p = Process(target=start_websocket_worker, args=(shared_pipeline.pipeline,))
        p.start()
        processes.append(p)
        
    # 等待所有进程结束
    for p in processes:
        p.join()

可以看到这里我是每个进程加载一次模型,然后每个进程里每路请求都是共享一个模型,这里可以节省非常多的显存。
首次尝试多进程的时候没有共享模型,导致每增加一路的并发就要加载一次模型,这样显存很快就爆了,增加了共享模型之后,每增加一个进程加载一次模型,显存的使用大大降低,这样最终限制并发路数的瓶颈就是GPU的使用率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值