简介
skynet
实现了一套调度器机制,用以调度 process
, 与云风大佬不同的是,sched
支持公平模式以及独占模式,独占模式主要是为了解决特性场景下业务的响应速度,从而提升体验感,
其次,不一定需要按照每个 process
对应一条协程,减少runtime
调度以及内存的开销
Sched
一个伪线程的逻辑处理器概念,它分为独占和负载两种模式。
-
独占是为了更好的处理实时性更高的业务,它不会被其他任务抢占
-
负载
又可分为两种运行态,均匀的处理业务以及从其他
process上偷窃任务,尽量保证
Processor不会过于闲置,除此之外,负载
Processor可随着任务的变动而增加(不会超过最大设定值),特别的当某个任务陷入”死循环”或者是超出设定运行阈值的时候会重新创建一个
Processor`,并让之前的挂起(在C版本中将会被强制关闭)。 -
多数时候协程过多会造成系统压力。
C版本和Go版本调度和设计上差异不大,但一些细节上的处理可能不同,因为C可以提供更多的底层控制
Process
process
是一种用户态的伪概念,用于描述一个 actor
的具体实现方式,也是 skynet
最小调度单元,这种概念对于分布式而言更友好,无关乎process在哪,只需要知道 PID
或者 Alias
即可向其投送消息。
主要是对业务几乎无侵入
Message
message
是 skynet
基础消息承载结构
服务的消息队列
Actor
模型最重要的的概念是 mailbox
,它代表了一个实体需要处理的队列容器,
得益于go
的简单性,可以使用 channel
来实现,但这种方式的实现性能不高,因为 channel
底层的结构使用的是互斥锁,
所以我采用了mpsc
实现了无锁队列,性能更优于 channel
TODO: 吞吐量对比
消息的接受和发送
- 发送
用户不需要构建这个结构体,仅仅需要指定 dest
以及需要发送的数据,而且 skynet
消息投递被设计成不允许发送 nil
因为这是无任何意义的,相反它还会消耗服务投递的性能,如果确实有这种需求,可以发送 struct{}{}
。
至于这个节点是再本地,还是其他地方并不重要
- 接收
接受回调只包含5
个关键参数 context
,addr
,session
,mtype
,msg
,size
-
context
其实就是创建process
指定的结构指针,用于表示处理上下文 -
addr
即为投递者的Pid
,(需要注意的是,skynet
支持redirect
以及fake
模式,所以这地址需要在发送的时候明确) -
session
主要的作用是用以区分这条消息是否是同步请求, 如若大于0,则其值就是请求序列号,只需要通过skynet.ret(msg)
返回即可 -
mtype
仅仅是一个消息类别的区分,类似于消息号,用户可自行定义,可作为rpc
消息类型 -
argument
才是真实的数据,它可以是任意值,特别的,在lua
中这个值是会被解构,在跨节点通讯这个值恒为[]byte
,当不需要时记得 skynet.free1.4.0 这个由底层回收,用户不用关心
异步消息
异步消息通过 skynet.send
的方式进行投递,它只在乎这个消息有没有正确投递出去,而不关心是否能被对点服务正确处理
由于是基于mailbox
所有消息都是异步处理的,意味着时延性平均略高于同步
同步消息
说是同步消息 其实本质上还是异步,这个不属于skynet
的底层内容而是在上层基于业务需求而封装的 伪
同步