Skip to content

Latest commit

 

History

History
389 lines (270 loc) · 3.74 KB

File metadata and controls

389 lines (270 loc) · 3.74 KB

Xtra 学习笔记

一句话理解

Xtra 本质上是:

mpsc + 状态(State) + 消息(Message) + Handler

或者:

Actor = 有状态的 Service

核心概念

Actor

Actor 就是一个长期存活的对象。

#[derive(xtra::Actor)]
struct Printer {
    times: usize,
}

理解为:

Actor = Service

例如:

MqttActor
P2PActor
WebSocketActor
DeviceActor

State

Actor 内部字段就是状态。

struct Printer {
    times: usize,
}

这里:

times

就是状态。

状态只能由 Actor 自己修改。


Message

Message 就是命令。

struct SayHello(String);

相当于:

enum Cmd {
    SayHello(String)
}

所以:

Message = Cmd

Handler

消息处理器。

impl Handler<SayHello> for Printer {
    type Return = ();

    async fn handle(
        &mut self,
        msg: SayHello,
        _ctx: &mut Context<Self>,
    ) {
        self.times += 1;

        println!(
            "Hello {}, 第 {} 次调用",
            msg.0,
            self.times
        );
    }
}

相当于:

match cmd {
    Cmd::SayHello(...)
}

所以:

Handler = match Cmd

Address

Actor 地址。

Address<Printer>

相当于:

Sender<Cmd>

发送消息:

addr.send(...)

等价于:

tx.send(...)

所以:

Address = Sender

Mailbox

邮箱。

Mailbox::bounded(32)

相当于:

mpsc::channel(32)

作用:

缓存消息
排队等待处理

所以:

Mailbox = Receiver + Queue

Actor 生命周期

创建

let (addr, mailbox) =
    Mailbox::bounded(32);

xtra::spawn_tokio(
    Printer::new(),
    (addr.clone(), mailbox),
);

发送消息

addr.send(
    SayHello("Tom".into())
)
.await?;

处理消息

impl Handler<SayHello> for Printer

停止

drop(addr);

或者:

ctx.stop_self();

对照 Tokio

Tokio 写法:

enum Cmd {
    Set(String),
    Get,
}
let (tx, rx) =
    mpsc::channel(32);
while let Some(cmd) =
    rx.recv().await
{
    match cmd {
        ...
    }
}

Xtra 写法:

struct Set(String);

struct Get;
Address<MyActor>
impl Handler<Set>
impl Handler<Get>

关系映射

Tokio Xtra
Service Actor
State Actor字段
Cmd Message
Sender Address
Receiver Mailbox
match Cmd Handler
spawn task spawn_actor

推荐模式

Actor 自己负责启动

impl Printer {
    pub fn start() -> Address<Self> {

        let (addr, mailbox) =
            Mailbox::bounded(32);

        xtra::spawn_tokio(
            Self {
                times: 0,
            },
            (addr.clone(), mailbox),
        );

        addr
    }
}

使用:

let printer =
    Printer::start();

Tauri 推荐结构

启动时创建一次:

let printer =
    Printer::start();

tauri::Builder::default()
    .manage(printer)

Command:

#[tauri::command]
pub async fn hello(
    name: String,
    printer: State<'_, Address<Printer>>,
) -> Result<(), String> {

    printer
        .send(
            SayHello(name)
        )
        .await
        .map_err(|e| e.to_string())
}

最重要的记忆

Actor = 有状态的 Service

Message = Cmd

Address = Sender

Handler = match Cmd

Mailbox = 消息队列

如果记住这五句话,已经掌握 Xtra 80% 的内容。