#actor #messages #supervisor #async #send-message

murray

使用Tokio的最小actor定义宏

7个不稳定版本 (3个破坏性版本)

0.4.2 2022年10月9日
0.4.1 2022年10月9日
0.3.0 2022年5月9日
0.2.0 2022年5月8日
0.1.1 2022年5月7日

#788 in 异步

MIT 许可证

21KB
325

Murray

murray crate提供了一个actor!宏,该宏有助于定义受Erlang启发的actor。actor针对异步和tokio,但可以通过使用其他mpsc通道进行适配。

使用

struct MyMsg {
 s: String
 }

actor! {
    Foo,
    Messages: {
        Msg1,
        Msg2 MyMsg,
        Msg3 { ch: mpsc::Receiver<String> }
    }
}

actor! {
    Bar,
    Options: {
        sup: Foo,
        id: String,
    },
    Messages: {
        A,
        B {
            x: bool,
        },
    },
    State: {
        foo: TypeC,
    }
}

impl FooActor {
    async fn handle_msg1(&self, state: &mut FooActorState)  {
	...
    }
    async fn handle_msg2(&self, state: &mut FooActorState, msg: MyMsg)  {
	...
    }
    async fn handle_msg3(&self, state: &mut FooActorState, msg: FooActorMessagesMsg3)  {
	...
    }
}

impl BarActor {
    async fn handle_a(&self, state: &mut BarActorState)  {
	...
    }
    async fn handle_b(&self, state: &mut BarActorState, msg: BarActorMessagesB)  {
	...
    }
    fn init(&self, state: &mut BarActorState) {
	...
    }
}

let sup = FooActor{}.start();
let id = String::from("abar");
let abar = BarActor{}.start(sup, &id);

abar.send(BarActorMessages::B(true));

这将生成struct FooActorenum FooActorMessages和一个struct FooActorState(Bar的类似)。如果您包含Options,它们可能包含一个sup属性,命名代理的supervisor基本名称,以及一个id属性,命名actor的id类型。该类型必须是Clone。

State结构包括一个tx Sender通道,以便您的处理器可以向actor发送消息。如果actor有supervisor,它还将包括一个sup_ch和一个id字段,如果它在选项中包含。actor定义包括一个带有额外属性的State,它们将作为Option初始化为None。如果您有额外的属性,actor::start将在开始处理消息之前调用self.init

此宏将具有属性的消息变体扩展到相应的具有属性的结构体(struct),以便在处理函数中更容易处理。因此,对于Foo,宏生成一个struct FooActorMessagesMsg3,但没有生成struct FooActorMessagesMsg1struct FooActorMessagesMsg2,并期望您提供FooActor::handle_msg1FooActor::handle_msg2FooActor::handle_msg3。处理函数是async并返回()。所有与actor的通信都通过state.tx通道进行。记住,您的处理函数不能拥有通道,您需要移动一个clone

更多示例请参阅murray-tests存储库。

注意事项

FooActorMessagesMsg1是一个糟糕的标识符,宏应该提供更简短的版本。

目前还没有实际的上层管理,但另一方面,没有actor隔离,因此崩溃会摧毁一切。

actor是什么?

Actor模型是一种并发计算模型,其中"actor"是具有完全封装状态的独立计算单元。actor外部的世界只能通过向其发送消息与actor进行通信。作为对消息的响应,actor可以改变其状态、发送消息并创建更多actor。从概念上讲,它与通信顺序程序类似,这是Golang运行时实现的计算模型。

actor模型有三个使其越来越相关的特性

  • 完整的"对象"封装
  • 无共享
  • 无锁并发

actor状态中没有外部干扰,且actor之间没有共享或全局状态,这消除了竞争条件类型错误(例如,线程A在没有线程B知晓的情况下修改共享值)。这加上actor总是可以前进,因为它们不依赖于外部资源(无锁并发),允许编写能够自动并行化的安全程序,以适应当前的多核硬件。

在Rust中使用actor并不能使您的程序万无一失,特别是与使用Erlang相比。Erlang虚拟机将actor隔离,就像它们是Unix进程一样,因此actor中的错误不会影响其他actor(事实上,Erlang的座右铭是让它崩溃)。Rust是一种基于堆的语言,崩溃错误(例如,一个unwrap panic)将使整个程序崩溃。

依赖关系

~79KB