Rust生态系统中一个纯Rust实现的Actor框架——Ractor。构建于Tokio之上。
它受Erlang的gen_server启发,同时具备Rust的速度和性能优势!
引言
在软件开发中,时间是有限的资源。你和我只有一小段时间来编写软件。而在同样的时间块内,有些人能够构建出令人惊叹的软件,而另一些人则困在项目的边缘,进行一些他们从未真正理解的小改动。你可能会认为这是随机的,或者试图找出为什么有些人能极大地提高生产力,而另一些人却在同样的问题上反复挣扎。
在你对我竖起叉子之前,我并不是在谈论那些在财务上取得成功或拥有大量用户的软件。我们都知道,与其他产品相比,Microsoft Teams的质量并不出众,但它拥有数量级更多的用户。商业策略如捆绑销售可能使产品质量变得无关紧要,只要你关注的是用户数量。我所说的是构建优秀的软件;我希望开发出其他像我一样喜欢的软件。你不也是这样吗?
一些需要记住的符号
在深入本教程之前,有几个符号需要澄清,以便读者能够更好地理解内容。
消息传递的Actors
由于我们试图尽可能地模仿Erlang的实践,Ractor中的消息发送可以通过两种方式进行:
- First-and-Forget(发送后不等待回复):对应Erlang中的
cast。 - 等待回复(等待消息处理后的回复):对应Erlang中的
call。
这种命名方式遵循了Erlang的命名约定,使得开发者在使用Ractor时能够更容易理解和上手。
安装Ractor
要在你的Rust项目中使用Ractor,只需在Cargo.toml文件的依赖部分添加以下内容:
[dependencies]
ractor = "0.9"
然后运行cargo build以安装Ractor。
第一个Actor
当然,我们需要从标志性的“Hello World”示例开始。我们希望构建一个Actor,每收到一条消息就打印“Hello World”。首先,我们定义消息类型,然后定义Actor本身。
定义消息类型
pub enum MyFirstActorMessage {
/// 打印“Hello World”
PrintHelloWorld,
}
定义Actor
use ractor::{Actor, ActorRef, ActorProcessingErr};
pub struct MyFirstActor;
#[async_trait::async_trait]
impl Actor for MyFirstActor {
type State = ();
type Msg = MyFirstActorMessage;
type Arguments = ();
async fn pre_start(&self, _myself: ActorRef<Self::Msg>, _arguments: Self::Arguments)
-> Result<Self::State, ActorProcessingErr>
{
Ok(())
}
}
解析
-
结构体定义:首先定义一个空的结构体
MyFirstActor,它将作为我们的Actor。 -
实现
Actortrait:通过#[async_trait::async_trait]宏实现Actortrait,定义以下关联类型:State:Actor的状态,这里是空的(),表示无状态。Msg:Actor处理的消息类型,即我们定义的MyFirstActorMessage。Arguments:Actor启动时的参数,这里也是空的()。
-
pre_start方法:定义Actor启动时的初始化逻辑,这里我们返回一个空的状态Ok(())。