Actor, 状态机, 事件
我一般都是将 Actor 和 状态机 当作关联概念理解, 一般来说状态机都是说的是有限状态机( finite-state machine|FSM ),
可以理解为设备/服务等具有多个状态并且允许切换转让.
也就是可以把服务抽象当作风扇, 对于风扇来说有以下状态:
- 开启
- 关闭
- 微风
- 中风
- 大风
这种抽象出来就是完全的状态机, 它具有内置多种状态, 而其中内部允许含有几种术语:
state(状态): 内部服务的状态, 这就是状态机内部核心, 所有系统行为都是围绕状态处理.transition(转换): 这里指的是将状态A切换成状态B的过程, 也就是定义状态机切换过程相关动作.transition condition(转换条件): 也就是常常听过的事件切换(Event), 用于触发转换方法从而切换状态action(行为): 状态运转的时候的切换动作, 如开始执行(initialize), 退出执行(exit), 转换行为(transition)等
这里需要先有状态机概念, 后续基本上都是这种概念的延申
状态机驱动如下:
// 这里采用伪造代码驱动, 假设创建状态机
let rt = Runtime
// 注册内部事件
rt.register('initialize',{ 驱动初始化事件 })
rt.register('exit', { 驱动退出事件 } )
// 自强定义切换事件
rt.transducers( state {
// 确定调用时候状态切换
switch state {
case '微风': // 切换成风扇微风
case '中风': // 切换成风扇中风
case '大风': // 切换成风扇大风
}
})
// 执行状态机让其运行
loop {
let err = rt.exec()
if err {
// 错误的时候直接退出状态机
exit 1
}
}
这就是简单的状态机概念, 现实很多事物都能抽象成这种概念处理.
说完状态机还需要说明下事件化处理( Event ), 计算机概念当中的 事件编程 也是指代这种概念.
在计算机当中的函数方法是作为事件块封装起来, 而内部集合自身独有属性, 对于事件带有以下操作:
wait(等待): 事件挂起等待唤醒执行set(切换可用): 将事件切换为可被调度唤醒可用状态clear(切换不可用): 同步告诉事件当前不可用, 可能处理中或者异常.
Actor模型
早年之前编写多核线程时候, 常规手段基本为 锁(Lock) 和 共享内存(SharedMemory), 但是在工作一段时间发现另外并发模型 Actor.
和
Linux的一切皆为文件(描述符)思想差不多,Actor崇尚任何事物都是 Actor 对象.
在多线程当中编写业务的时候常常在多核调度线程执行业务逻辑(玩家交易|HP扣除)等都需要加锁保证数据安全, 但是加锁在实时要求高带来的性能损耗极其巨大.
数据竞争|数据竞态: 如果不对数据占有处理, 会出现同个线程同时扣除|增加同份数据的危险
Actor 模型当中最出名的编程语言是 Erlang, 在其中以 进程 来代称并且内部带有 自愈 机制, 当异常崩溃的时候会自动修改崩溃状态并重启.
% 建立一个进程并启用函数web:start_server(Port, MaxConnections)
ServerProcess = spawn(web, start_server, [Port, MaxConnections]),
% 建立一个远程进程并启用函数
% web:start_server(Port, MaxConnections)于机器RemoteNode
RemoteProcess = spawn(RemoteNode, web, start_server, [Port, MaxConnections]),
% 发送消息到ServerProcess(异步的)。消息包含一个元组
% 它具有原子"pause"和数"10"。
ServerProcess ! {pause, 10},
% 接收发给这个进程的消息
receive
a_message -> do_something;
{data, DataContent} -> handle(DataContent);
{hello, Text} -> io:format("Got hello message: ~s", [Text]);
{goodbye, Text} -> io:format("Got goodbye message: ~s", [Text])
end.
对于高吞吐/低延迟的系统, 都可以采用
Actor机制,Actor简略:Actor Model of Computation.
上面已经介绍过状态机了, 而且 Actor 就是对状态机的具体实现模型, 其中 Actor 内置需要实现:
Thread:Actor具体还是需要集成多线程来做最大规模利用多核, 从而才能做到异步调用Timer: 定时器来执行调度Actor执行绪MailBox: 每个Actor通过内部消息队列获取消息执行, 外部和内部的交流仅作为消息推入内部队列
Actor 内部采用单线程处理来执行, 内部采用
任其崩溃原则内部直接崩溃就写入记录并重新初始化 Actor, 不做进行任务异常崩溃的停顿.
这里推荐参考 Rust 项目, 这是相对简单的 Actor 模型:
riker