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 !