You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中Socket接收缓慢:异步RPC调用性能分析求助

优化异步TCP RPC调用的Socket接收性能

先给你揪出几个关键问题,再一步步解决——你的代码里不仅有Socket接收的性能瓶颈,还有个容易忽略的协程调用bug,咱们从最影响性能的点开始说:

1. 必须复用TCP长连接(最核心的优化)

我猜你的client.call每次调用都会新建一个TCP连接?如果是这样,10000次请求的TCP握手+挥手开销直接把时间拉满了!这绝对是耗时25秒的主要原因。

改成复用单个长连接,所有RPC请求走同一个连接:

import asyncio
import json
import socket
import time

class ReusableRPCClient:
    def __init__(self):
        self.reader = None
        self.writer = None

    async def connect(self, host, port):
        # 只在初始化时建立一次连接
        self.reader, self.writer = await asyncio.open_connection(host, port)
        # 顺便调整缓冲区大小,后面会详细说
        self.writer.transport.get_extra_info('socket').setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 65536)
        self.reader._transport.get_extra_info('socket').setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536)

    async def call(self, params):
        # 复用已建立的连接发送请求
        self.writer.write(json.dumps(params).encode())
        await self.writer.drain()
        # 接收响应(如果你的RPC有固定协议,可以改成先读长度再读内容,避免截断)
        response_data = await self.reader.read(4096)
        return json.loads(response_data.decode())

# 全局复用一个客户端实例
client = ReusableRPCClient()

async def rpc_call(params):
    # 原代码这里漏了await!直接返回协程对象等于没执行调用,这是大bug
    return await client.call(params)

async def test():
    # 替换成你的实际请求参数
    await rpc_call({"id": 1, "method": "target_method"})

async def main():
    await client.connect('your-rpc-server-host', 1234)
    # 控制并发数,避免网络和服务器过载
    semaphore = asyncio.Semaphore(200)
    
    async def bounded_task():
        async with semaphore:
            await test()
    
    tasks = [asyncio.create_task(bounded_task()) for _ in range(10000)]
    await asyncio.gather(*tasks)

# 用uvloop提升事件循环性能(可选但效果明显)
try:
    import uvloop
    asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
except ImportError:
    pass

start = time.time()
asyncio.run(main())
end = time.time()
print(f"Total time: {end - start:.2f} seconds")

重点提醒:原代码里rpc_call函数的client.call(params)没有加await,这会直接返回一个协程对象,根本没实际执行RPC调用,这也是导致你测试结果不准的原因之一!

2. 调整Socket缓冲区大小

默认的TCP接收缓冲区很小,会导致操作系统频繁触发接收中断,增加系统调用开销。上面的代码里已经把发送和接收缓冲区调到64KB,你可以根据实际请求大小再调整(比如128KB),能减少数据接收的次数,提升整体效率。

3. 控制并发数量,避免过载

一下子扔10000个异步任务给事件循环,会导致网络队列、文件描述符被占满,反而让每个请求的等待时间变长。用asyncio.Semaphore限制同时执行的请求数(比如200),既能利用异步IO的并发优势,又不会压垮服务器和网络。

4. 优化序列化和RPC框架

如果你的自定义RPC实现比较简单,可以换用更高效的序列化方式,比如msgpack(比JSON快很多,数据体积也更小);或者直接用成熟的异步RPC框架,比如grpc.aio(gRPC的异步版本)、aiohttp做HTTP RPC,这些框架已经帮你做了底层的连接复用、缓冲区优化等工作。

5. 换用更高效的事件循环

默认的asyncio事件循环性能一般,在Linux/macOS上可以用uvloop替代,它基于libuv实现,异步IO的处理速度能提升30%-50%左右,安装后只需要加几行代码就能启用(上面的示例里已经包含了)。


内容的提问来源于stack exchange,提问作者rajan sthapit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:45:22