电话
400 9058 355
Go 标准库 net/rpc 不支持真正异步调用,rpc.Client.Call 是同步阻塞方法;所谓异步需手动用 goroutine + channel 包装,每次调用须分配独立 reply 实例并发送结果到 channel。
Go 标准库的 net/rpc 本身不支持真正的异步调用(即调用后立即返回、结果通过回调或 channel 通知),它默认是同步阻塞的。所谓“异步 RPC”,实际需要你手动包装成非阻塞行为,核心思路是:用 goroutine 启动 client.Call,再通过 channel 或回调函数传递结果。
rpc.Client.Call 看起来不能异步?rpc.Client.Call 是同步方法 —— 它会阻塞直到响应返回、解码完成或发生错误。没有内置 callback 参数,也不返回 chan *rpc.Call。它的签名是:
func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error这意味着你无法在不改写底层逻辑的前提下“让它变异步”。所有“异步 RPC”方案,都是在它外面加一层并发控制。
这是最轻量、最可控的方式:启动 goroutine 执行 Call,把结果(包括 error)发到 channel。调用方用 select 或直接接收,避免阻塞主流程。
reply 和 error 变量,不能复用(否则并发时数据竞争)chan struct{ Reply interface{}; Err error },避免类型断言开销*MyResponse),需确保传入的是新分配的实例,例如 &MyResponse{}
func AsyncCall(client *rpc.Client, serviceMethod string, args interface{}) chan struct{ Reply interface{}; Err error } {
ch := make(chan struct{ Reply interface{}; Err error }, 1)
go func() {
reply := &MyResponse{} // 必须每次 new
err := client.Call(serviceMethod, args, reply)
ch <- struct{ Reply interface{}; Err error }{Reply: reply, Err: err}
}()
return ch
}
// 使用
ch := AsyncCall(client, "Arith.Multiply", &Args{7, 8})
result := <-ch // 非阻塞?不,这里仍会等;若要真正不等,用 select + default
if result.Err != nil {
log.Println("RPC failed:", result.Err)
} else {
log.Printf("Got result: %+v", result.Reply)
}
如果你更习惯 Node.js 式的 callback(err, data),可以封装一个接受函数的版本。注意:回调函数里访问的变量需显式捕获,尤其不要在循环中直接引用循环变量。
err 是否为 nil,再对 reply 做类型断言或使用func CallWithCallback(client *rpc.Client, serviceMethod string, args interface{}, cb func(*MyResponse, error)) {
go func() {
reply := &MyResponse{}
err := client.Call(serviceMethod, args, reply)
cb(reply, err)
}()
}
// 使用
CallWithCallback(client, "Arith.Multiply", &Args{7, 8}, func(resp *MyResponse, err error) {
if err != nil {
log.Println("Callback error:", err)
return
}
log.Printf("From callback: %d", resp.Prod)
})
标准 RPC 的连接是长连接,但 Call 失败(如超时、网络断开)后,*rpc.Client 不会
自动重连。你得自己监听 client.Close() 或错误,重建 client。另外,Go 的 net/rpc 默认用 Gob 编码,服务端和客户端结构体字段必须首字母大写且类型一致,否则 reply 解码为空也不报错 —— 这类静默失败最容易让人卡住。
邮箱:8955556@qq.com
Q Q:8955556
本文详解如何将Go官方present工具(用于生成HTML5...
PySNMP在不同版本中对SNMP错误状态(errorSta...
time.Sleep仅阻塞当前goroutine,其他gor...
PHPfopen()创建含特殊符号的文件名失败主因是操作系统...
WooCommerce中通过代码为分组产品动态聚合子商品的属...
io.ReadFull返回io.ErrUnexpectedE...
本文详解Yii2中控制器向视图传递ActiveRecord数...
本文详解为何通过wp_set_object_terms()为...
Pytest中使用@mock.patch类装饰器会导致补丁泄...
带缓冲的channel是并发安全的FIFO队列;make(c...