MeteorCat / Actor,状态机,事件

Created Mon, 02 Oct 2023 22:29:24 +0800 Modified Wed, 29 Oct 2025 23:25:05 +0800
1474 Words

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