Skip to content
liangmanlin edited this page May 19, 2021 · 6 revisions

gootp 的核心库,提供类似erlang的supervisor,gen_server功能。

关于进程实现:

Actor 的实现,在第一版是使用interface实现的,后来发现这样没办法热更新,所有后面改为使用全局变量,作为 Actor 的回调模块。

根据benchmark测试,使用全局变量函数会比原生函数的执行多消耗 1ns,如果你特别注重这个性能,尽量少使用,此举完全是为了热更新。

type InitFunc func(ctx *Context,pid *Pid, args ...interface{}) unsafe.Pointer
type HandleCastFunc func(ctx *Context, msg interface{})
type HandleCallFunc func(ctx *Context, request interface{}) interface{}
type TerminateFunc func(ctx *Context, reason *Terminate)
type ErrorHandleFunc func(ctx *Context, err interface{}) bool

type Actor struct {
	// 初始化回调
	Init InitFunc
	// 接收消息
	HandleCast HandleCastFunc
	// 接收同步调用
	HandleCall HandleCallFunc
	// actor退出回调
	Terminate TerminateFunc
	// 当发生catch错误时调用,如果返回false,那么进程将会退出
	ErrorHandler ErrorHandleFunc
}

以上是Actor的数据结构,你只需要实现里面的函数,就可以调用kernel.Start启动一个进程服务。

主要api列表:

[kernel]

  • KernelStart(start func(),stop func())

    核心函数,所有自有逻辑都必须在start函数中实现,框架启动完成后,会执行start()。如果你有一些逻辑需要优先关闭,你可以传入 stop 函数。

    !!!如果你使用了gootp/gate 库,请务必传入一个stop函数,如:

    func stopGame(){
      gate.Stop()
    }

如需停止服务,调用kernel.InitStop()

或者通过网页请求:curl "http://127.0.0.1:3000/stop"

框架会根据服务启动的顺序,倒序关闭服务,最后退出。

[gen_server]

  • Start(newActor *Actor, args ...interface{}) (*Pid, interface{}) 启动一个匿名进程。

  • StartName(name string, newActor *Actor, args ...interface{}) (*Pid, interface{}) 启动一个带名字的进程。

  • Cast(pid *Pid, msg interface{}) 向一个进程发生一个cast消息,你可以在HandleCast回调中处理。

  • CastName(name string, msg interface{})

  • CastNameNode(name string, node interface{}, msg interface{}) 向一个分布式节点发送cast消息。

  • Call(pid *Pid, request interface{}) (bool, interface{}) 向一个进程发起同步调用,你可以在HandleCall回调中处理。

  • CallName(name string, request interface{}) (bool, interface{})

  • CallNameNode(name string, node interface{}, request interface{}) (bool, interface{}) 向一个分布式节点的进程发起同步请求。

  • CallTimeOut(pid *Pid, request interface{}, timeOut time.Duration) (bool, interface{}) 向一个进程发起同步调用,可以指定超时时间(秒)。

[Context]

也有一批类似的api

  • (c *Context) CastName(name string, msg interface{})

  • (c *Context) CastNameNode(name string, node interface{}, msg interface{})

  • (c *Context) Cast(pid *Pid, msg interface{})

  • (c *Context) CallName(name string, request interface{}) (bool, interface{})

  • (c *Context) Call(pid *Pid, request interface{}) (bool, interface{})

  • (c *Context) CallNameNode(name string, node interface{}, request interface{}) (bool, interface{})

  • (c *Context) StartLink(newActor *Actor, args ...interface{}) (*Pid, interface{})

  • (c *Context) StartNameLink(name string, newActor *Actor, args ...interface{}) (*Pid, interface{})

更多可以自行查阅

[supervisor]

  • SupStart(name string, initChild []*SupChild) *Pid 启动一个监控进程,如果传入了initChild,那么 child 也会被启动。

  • SupStop(sup interface{}) 关闭一个监控进程,同时他的 child 也会被关闭。

  • SupStartChild(sup interface{}, child *SupChild) (interface{}, *Pid) 启动一个 child 进程,并且把进程挂载在监控进程下面。

  • SupWhichChild(sup interface{}) []*SupChildInfo 获取监控进程下的所有子进程。

gootp/kernel/time.go 提供了一些基础的时间函数,可以自行查阅。

gootp/kernel/timer.go 提供类似erlang:send_after的功能。

  • SendAfter(timerType timerType, pid *Pid, inv int64, msg interface{})

[logger]

框架提供了一个记录logger日志的功能,目前只有2个日志级别。

  • DebugLog(format string, args ...interface{})

  • ErrorLog(format string, args ...interface{})

你只需要配置一个环节变量:

kernel.Env.WriteLogStd = true  // 是否输出到控制台
kernel.Env.LogPath = "../logs" // 如果不填,默认输出到 `./log` ,也可以填 "",表示不记录到文件
kernel.KernelStart(initGame,stopGame)

如果你不喜欢使用这个日志库,你可以在kernel.KernelStart(initGame,stopGame)启动前,调用:

  • kernel.TouchLogger(writer io.Writer)

    接管所有的日志消息,你不需要担心线程安全问题,因为上层是单线程执行的。

kernel 提供了一个特殊数据结构 kernel.KMsg

该数据结构可以直接发往分布式节点上,前提是你注册了KMsg.Msgnode中。

更多api你可以通过Goland查阅。

Clone this wiki locally