grpc-go与actor模式
(金庆的专栏 2018.6)
grpc-go服务器的每个请求都在一个独立的协程中执行。
网游服务器中,一般请求会调用游戏房间的方法,而房间是一个独立的协程。
可以将房间实现为actor,grpc请求通过Call()或Post()方法来执行。
其中Call()会等待返回,而Post()会异步执行无返回值。
type Room struct {
// actC 是其他协程向Room协程发送动作的Channel,协程中将依次执行动作。
// Action 动作, 是无参数无返回值的函数.
actC chan func()
...
}
// Run 运行房间协程.
func (r *Room) Run() {
ticker := time.NewTicker(20 * time.Millisecond)
defer ticker.Stop()
for r.running {
select {
case act := <-r.actC:
act()
case <-ticker.C:
r.tick()
}
}
}
// Call calls a function f and returns the result.
// f runs in the Room's goroutine.
func (r *Room) Call(f func() interface{}) interface{} {
// 结果从ch返回
ch := make(chan interface{}, 1)
r.actC <- func() {
ch <- f()
}
// 等待直到返回结果
return <-ch
}
// Post 将一个动作投递到内部协程中执行.
func (r *Room) Post(f func()) {
r.actC <- f
}
grpc服务方法如:
func (m *RoomService) Test(ctx context.Context, req *pb.TestReq) (*pb.TestResp, error) {
conn := conn_mgr.GetConn(ctx)
if conn == nil {
return nil, fmt.Errorf("can not find connection")
}
room := conn.GetRoom()
resp := room.Call(func() interface{} {
return room.Test(req)
})
return resp.(*pb.TestResp), nil
}