1 个不稳定版本
0.9.0 | 2020年1月18日 |
---|
#1040 在 异步
在 2 crates 中使用
225KB
5K SLoC
Actix
Actix 是一个 Rust Actor 框架。
- 用户指南
- API 文档(开发版本)
- API 文档(发布版本)
- Cargo 包: actix
- 最低支持的 Rust 版本: 1.39 或更高
功能
- 异步/同步 Actor。
- 本地/线程上下文中的 Actor 通信。
- 使用 Futures 进行异步消息处理。
- HTTP1/HTTP2 支持 (actix-web)
- Actor 监督。
- 类型化消息(无
Any
类型)。
用法
要使用 actix
,将以下内容添加到您的 Cargo.toml
[dependencies]
actix = "0.9"
初始化 Actix
为了使用 actix,您首先需要创建一个 System
。
fn main() {
let system = actix::System::new("test");
system.run();
}
Actix使用了tokio事件循环。System::new()
创建了一个新的事件循环并启动了System
演员。system.run()
启动了tokio事件循环,一旦System
演员收到SystemExit
消息,则结束。
让我们创建一个简单的Actor。
实现Actor
为了定义一个actor,你需要定义一个struct,并让它实现Actor
特质。
use actix::{Actor, Addr, Arbiter, Context, System};
struct MyActor;
impl Actor for MyActor {
type Context = Context<Self>;
fn started(&mut self, ctx: &mut Self::Context) {
println!("I am alive!");
System::current().stop(); // <- stop system
}
}
fn main() {
let system = System::new("test");
let addr = MyActor.start();
system.run();
}
通过Actor特质的start
和create
方法来创建一个新的actor。它提供了创建actor的多种方式,具体详情请查看文档。你可以实现Actor特质的started
、stopping
和stopped
方法。started
在actor启动时被调用,stopping
在actor结束时被调用。查看API文档了解更多关于actor生命周期的信息。
处理消息
Actor通过发送消息与其他Actor进行通信。在actix中,所有消息都是类型化的。让我们定义一个简单的带有两个usize
参数的Sum
消息,并创建一个接受这个消息并返回这两个数字之和的actor。
use futures::{future, Future};
use actix::*;
// this is our Message
struct Sum(usize, usize);
// we have to define the response type for `Sum` message
impl Message for Sum {
type Result = usize;
}
// Actor definition
struct Summator;
impl Actor for Summator {
type Context = Context<Self>;
}
// now we need to define `MessageHandler` for the `Sum` message.
impl Handler<Sum> for Summator {
type Result = usize; // <- Message response type
fn handle(&mut self, msg: Sum, ctx: &mut Context<Self>) -> Self::Result {
msg.0 + msg.1
}
}
fn main() {
let sys = System::new("test");
let addr = Summator.start();
let res = addr.send(Sum(10, 5)); // <- send message and get future for result
Arbiter::spawn(res.then(|res| {
match res {
Ok(result) => println!("SUM: {}", result),
_ => println!("Something wrong"),
}
System::current().stop();
future::result(Ok(()))
}));
sys.run();
}
所有与actor的通信都通过一个Addr
对象进行。你可以使用do_send
发送消息而不等待响应,或者使用特定消息发送actor。Message
特质定义了消息的结果类型。
Actor状态和特定消息的订阅
你可能已经注意到,Actor
和Handler
特质的 方法接受&mut self
,因此你可以将任何东西存储在actor中,并在必要时对其进行修改。
地址对象需要一个actor类型,但如果我们只想向可以处理该消息的actor发送特定消息,我们可以使用Recipient
接口。让我们创建一个新的使用Recipient
的actor。
use std::time::Duration;
use actix::prelude::*;
#[derive(Message)]
struct Ping { pub id: usize }
// Actor definition
struct Game {
counter: usize,
addr: Recipient<Ping>,
}
impl Actor for Game {
type Context = Context<Game>;
}
// simple message handler for Ping message
impl Handler<Ping> for Game {
type Result = ();
fn handle(&mut self, msg: Ping, ctx: &mut Context<Self>) {
self.counter += 1;
if self.counter > 10 {
System::current().stop();
} else {
println!("Ping received {:?}", msg.id);
// wait 100 nanos
ctx.run_later(Duration::new(0, 100), move |act, _| {
act.addr.do_send(Ping{id: msg.id + 1});
});
}
}
}
fn main() {
let system = System::new("test");
// To get a Recipient object, we need to use a different builder method
// which will allow postponing actor creation
let addr = Game::create(|ctx| {
// now we can get an address of the first actor and create the second actor
let addr = ctx.address();
let addr2 = Game{counter: 0, addr: addr.recipient()}.start();
// let's start pings
addr2.do_send(Ping{id: 10});
// now we can finally create first actor
Game{counter: 0, addr: addr2.recipient()}
});
system.run();
}
聊天示例
有一个聊天示例,它提供了一个基本示例,展示了网络客户端/服务器服务。
fectl
你可以考虑查看fectl工具。它使用actix
编写,展示了如何创建具有相对复杂交互的网络应用程序。
贡献
所有贡献都受欢迎,如果你有一个功能请求,请毫不犹豫地打开一个问题!
许可协议
本项目采用以下任一许可协议:
- Apache License,版本2.0,(LICENSE-APACHE或http://www.apache.org/licenses/LICENSE-2.0)
- MIT许可(LICENSE-MIT或http://opensource.org/licenses/MIT)
任选其一。
行为准则
对actix crate的贡献是在贡献者公约的条款下组织的,actix的维护者@fafhrd91承诺将介入以维护该行为准则。
依赖关系
~7–11MB
~212K SLoC