Python中Socket接收缓慢:异步RPC调用性能分析求助
先给你揪出几个关键问题,再一步步解决——你的代码里不仅有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

