erlang比go要成熟,其中一大原因就是拥有otp工程,进程的管理可以通过专门的行为
模式去处理,例如gen_server,里面包含的6个回调函数init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3
来实现进程的一系列行为,例如启动进程,异步调用,同步调用,响应,关闭进程等
先来看一段gen_server的内部实现代码:
-module(server_templat -export([start/1]). -export([call/2, cast/2]). -export([init/1]). %%通用进程模式(可以认为是c/s模型的阻塞和非阻塞) start(Mod) -> spawn(server_template, init, [Mod]). init(Mod) -> register(Mod, self()), State = Mod:init(), loop(Mod, State). loop(Mod, State) -> receive {call, From, Req} -> {Res, State2} = Mod:handle_call(Req, State), From ! {Mod, Res}, loop(Mod, State2); {cast, Req} -> State2 = Mod:handle_cast(Req, State), loop(Mod, State2); stop -> stop end. %% 接口部分 call(Name, Req) -> Name ! {call, self(), Req}, receive %% 这里就是阻塞在等待返回,精辟!!! {Name, Res} -> Res end. cast(Name, Req) -> Name ! {cast, Req}, ok.
能看懂erlang代码的,应该明白上面是什么意思。
下面是我用go来实现的
package global import ( "time" ) type PidObj struct { Callback GenServer reqCh chan GenReq replyCh chan Reply stop bool } type GenReq struct { Method string MsgData interface{} t int time int32 } type Reply interface{} const ( call = iota cast timer shutdown ) // Start server func RegisterPid(pidName interface{}, callback GenServer) *PidObj { pidObj := &PidObj{Callback:callback} pidObj.reqCh = make(chan GenReq, 1024) pidObj.replyCh = make(chan Reply, 1024) callback.Start() go pidObj.loop() return pidObj } func (p *PidObj) loop() { for { req := <-p.reqCh switch req.t { case call: reply := p.Callback.HandleCall(req) p.replyCh <- reply case cast: p.Callback.HandleCast(req) case timer: p.Callback.HandleInfo(req) //time.AfterFunc(time.Duration(req.time) * time.Second, func() { // p.Callback.HandleInfo(req) //}) case shutdown: p.stop = true close(p.reqCh) close(p.replyCh) p.Callback.Stop() return } } } func (p *PidObj) Call(method string, msg interface{}) (reply Reply) { p.reqCh <- GenReq{Method: method, MsgData: msg, t: call} reply = <-p.replyCh return } func (p *PidObj) Cast(method string, msg interface{}) { p.reqCh <- GenReq{Method: method, MsgData: msg, t: cast} } func (p *PidObj) SendAfter(method string, seconds int32, msg interface{}) { time.AfterFunc(time.Duration(seconds) * time.Second, func() { if !p.stop { p.reqCh <- GenReq{Method: method, MsgData: msg, t: timer, time:seconds} } }) } func (p *PidObj) Stop() { p.reqCh <- GenReq{t: shutdown} }
定义接口:
package global // GenServer behavior needs to implement this interface type GenServer interface { Start() HandleCall(GenReq) Reply HandleCast(GenReq) HandleInfo(GenReq) Stop() }
上面是用go实现了类似erlang的gen_server功能,使用的时候只需要实现Start, HandleCall,HandleCast,HandleInfo和Stop
这五个接口就可以了。
ok,that's all !