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 异步
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 FooActor
、enum 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 FooActorMessagesMsg1
或struct FooActorMessagesMsg2
,并期望您提供FooActor::handle_msg1
、FooActor::handle_msg2
和FooActor::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