python xmlrpc踩坑记录

最近用 Python 写了一个 RPC 服务,之前在 Ubuntu 上跑,换到 Windows 上之后突然发现一个神奇的问题。我的目的是在一个循环里定时获取设备状态,然后广播给订阅的客户端。获取设备状态是一个 RPC 接口。大致结构如下:

python 复制代码
proxy = xmlrpc.client.ServerProxy(f"http://localhost:8080/", allow_none=True)
subscribers = [] # 客户端连接
running = True
async def periodic_pusher():
    while running:
        await asyncio.sleep(0.05)
        if subscribers:
            data = proxy.get_data()
            payload = json.dumps(data)
            # 将 payload 广播给客户端
async def main(port):
    asyncio.create_task(periodic_pusher())
    async with websockets.serve(handler, "0.0.0.0", port):
        await asyncio.Future()

任务很简单,客户端通过 websocket 连接上来,然后订阅数据,这里为了照护客户端的实现者,所以转了一手。

因为配环境还挺麻烦的,而且我的数据并不复杂,所以选了 python 标准库自带的 xmlrpc 作为 rpc 库。换到 Windows 上以后,客户端突然变得异常卡顿,打印日志后发现差不多两秒多才能从服务的收到一个条数据,不管循环里 sleep 的时间调的多小都没用。

开始怀疑是异步任务调度的问题,试了纯 sleepprint,还是飕飕的。然后是排查服务端响应,还真有问题。

python 复制代码
def rpc_get_xxx():
     data = None
     while data is None:
         data = robot.get_xxx()
         time.sleep(0.01)
     return data

因为获取数据 API 可能会返回 None,所以用了循环来保证一定能获取到数据,data=None 导致一定会进入循环,也就导致 sleep 一定至少会执行一次,带来不必要的延时。知错就改,只要把 data=None 改成 data=robot.get_xxx() 就可以了。

再次测试,但是问题依然存在,rpc 服务端的延时顶多几十毫秒,websocket 客户端那边是一两秒的问题。没别的办法加日志吧,在 rpc 调用前后加上日志,发现一次 rpc 调用就要两秒多,为进一步定位问题,在 rpc 服务端也加上日志。试了几次,结果如下:

复制代码
before rpc: 1763365566.3031723
before get: 1763365568.3533354
after  get: 1763365568.3543353
after  rpc: 1763365568.3543353

before rpc: 1763367026.1716492
before get: 1763367028.228031
after  get: 1763367028.228031
after  rpc: 1763367028.228031

before rpc: 1763367290.863952
before get: 1763367292.9115446
after  get: 1763367292.9115446
after  rpc: 1763367292.9135447

rpc 客户端发起请求到服务端收到请求居然花了两秒多?这也太离谱了。。。

正当我怀疑 xmlrpc 库到底靠不靠谱的时候,找到看一篇帖子:

真是救命稻草,当我把 rpc 客户端的 ip 地址换成 127.0.0.1 之后,还真就解决了。一次调用几十毫秒就完成了:

复制代码
before rpc: 1763367422.9848952
before get: 1763367422.9868922
after  get: 1763367422.9868922
after  rpc: 1763367422.9880338

这才正常嘛,不过这个坑是真坑爹啊。


其实这个问题也问过 AI,它坚持说是 getfqdn 反解 DNS 的问题,还给了一段测试代码:

python 复制代码
import socket, time
t0 = time.perf_counter()
socket.getfqdn('localhost')   # 模拟 xmlrpc 内部调用
print("getfqdn 耗时:", time.perf_counter() - t0)

但是实际上这段代码运行起来非常快:

复制代码
getfqdn 耗时: 0.012044099974445999

帖子里也说了跳过 getfqdn 并没有用,所以应该不是它的问题。


相关推荐
独好紫罗兰1 小时前
对python的再认识-基于数据结构进行-a006-元组-拓展
开发语言·数据结构·python
Dfreedom.1 小时前
图像直方图完全解析:从原理到实战应用
图像处理·python·opencv·直方图·直方图均衡化
铉铉这波能秀1 小时前
LeetCode Hot100数据结构背景知识之集合(Set)Python2026新版
数据结构·python·算法·leetcode·哈希算法
怒放吧德德2 小时前
Python3基础:基础实战巩固,从“会用”到“活用”
后端·python
aiguangyuan2 小时前
基于BERT的中文命名实体识别实战解析
人工智能·python·nlp
喵手2 小时前
Python爬虫实战:知识挖掘机 - 知乎问答与专栏文章的深度分页采集系统(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·零基础python爬虫教学·采集知乎问答与专栏文章·采集知乎数据·采集知乎数据存储sqlite
铉铉这波能秀2 小时前
LeetCode Hot100数据结构背景知识之元组(Tuple)Python2026新版
数据结构·python·算法·leetcode·元组·tuple
kali-Myon2 小时前
2025春秋杯网络安全联赛冬季赛-day2
python·安全·web安全·ai·php·pwn·ctf
Olamyh2 小时前
【 超越 ReAct:手搓 Plan-and-Execute (Planner) Agent】
python·ai
deepxuan2 小时前
Day7--python
开发语言·python