
Go 标准库的 net/rpc 并不内置响应缓存机制;所谓“服务器已宕机却持续返回正确结果”,实为客户端未检查 RPC 调用错误,导致重复读取旧内存值或零值(如 int 类型的 0),在 Windows 上因调度/IO 行为差异易被误判为“缓存”,本质是逻辑缺陷而非缓存功能。
go 标准库的 `net/rpc` 并不内置响应缓存机制;所谓“服务器已宕机却持续返回正确结果”,实为客户端未检查 rpc 调用错误,导致重复读取旧内存值或零值(如 `int` 类型的 `0`),在 windows 上因调度/io 行为差异易被误判为“缓存”,本质是逻辑缺陷而非缓存功能。
在 Go 的 net/rpc 实现中,不存在任何形式的服务端或客户端响应缓存。RPC 调用是严格的一问一答同步(或异步)通信模型:每次 client.Go() 或 client.Call() 都会尝试通过底层连接发送请求,并等待响应。一旦连接中断(如服务端进程退出、VM 关机、网络不可达),后续调用理应失败——但若代码忽略错误处理,就会掩盖真实状态,造成“看似正常”的假象。
问题代码中的关键缺陷在于:从未检查 replyCall.Error。rpc.Call 的 Done 通道返回后,replyCall.Reply 仅表示内存地址已就绪,而 replyCall.Error 才是判断调用是否成功的唯一权威依据:
divCall = client.Go("Fibonacci.Calculate", args, &reply, nil)
go func() {
replyCall := <p>为什么会出现“杀掉服务器后仍打印结果”?原因如下:</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/ai/1509" title="知海图Chat"><img
src="https://img.php.cn/upload/ai_manual/000/000/000/175680205266506.png" alt="知海图Chat" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/ai/1509" title="知海图Chat" class="overflowclass">知海图Chat</a>
<p class="overflowclass">知海图Chat是基于知乎与面壁智能合作大模型能力的中文知识问答工具。</p>
</div>
<a rel="nofollow" href="/ai/1509" title="知海图Chat" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
- &reply 是一个栈/堆上分配的 *int 变量,初始值为 nil → 解引用前若未赋值,行为未定义;但更常见的是:rpc 包在调用失败时不会修改 reply 指向的内存,因此 reply 保持上次成功调用后的值(若变量作用域复用)或零值(如新声明的 var reply int 初始化为 0)。
- 在你的循环中,var reply int 是在循环外声明的,每次 client.Go(..., &reply, ...) 都复用同一内存地址。当 RPC 失败时,reply 值不变,仍为前一次计算结果(如 fib(9) 返回 34),从而产生“持续返回正确值”的错觉。
- Linux 与 Windows 差异源于 TCP 连接重试、RST 包处理、goroutine 调度时机等底层行为不同,但根本原因一致:未校验错误,盲目使用未更新的 reply 值。
✅ 正确实践要点:
- 永远检查 call.Error:这是 RPC 成功与否的黄金准则,不可省略。
- 避免 reply 变量复用:若需并发调用,应为每次请求分配独立 reply 变量(或使用结构体字段隔离)。
- 设置连接超时与健康检查:rpc.DialHTTP 不支持原生超时,建议封装 http.Client 并配置 Timeout,或改用 rpc.DialHTTPPath + 自定义 transport。
- 考虑现代替代方案:net/rpc 已趋于维护模式,生产环境推荐 gRPC(基于 HTTP/2,内置超时、重试、负载均衡)或 REST+JSON(更易调试与监控)。
总结:这不是 Go RPC 的“缓存特性”,而是典型错误处理缺失引发的隐蔽 bug。修复只需一行错误检查,却能杜绝灾难性静默失败——在分布式系统中,可观察性始于对每一个 error 的敬畏。










