版权声明:本文为BBDXF原创,如果转载请注明出处。 https://blog.csdn.net/bbdxf/article/details/87890150
actix 学习
Actix是一个rust库,它为并发应用程序的开发提供了一个框架。
Actix是基于Actor模型构建的,它允许将应用程序编写为一组独立执行但协作的“Actor”,这些“Actor”通过消息进行通信。Actor是封装状态和行为并在actix库提供的Actor系统中运行的对象。
参与者在特定的执行上下文上下文中运行。上下文对象仅在执行期间可用。每个参与者都有一个单独的执行上下文。执行上下文还控制参与者的生命周期。参与者仅通过交换消息进行通信。发送参与者可以选择等待响应。
角色不是直接引用的,而是通过地址引用的。任何rust类型都可以是actor,它只需要实现actor特征。为了能够处理特定的消息,参与者必须为该消息提供一个处理程序实现。所有消息都是静态类型的。消息可以以异步方式处理。
Actor可以生成其他Actor,或者向执行上下文添加期货或流。参与者特征提供了几个方法,允许控制参与者的生命周期。
简单例子
extern crate actix;
extern crate futures;
use std::io;
use actix::prelude::*;
use futures::Future;
/// Define message
struct Ping;
impl Message for Ping {
type Result = Result<bool, io::Error>;
}
// Define actor
struct MyActor;
// Provide Actor implementation for our actor
impl Actor for MyActor {
type Context = Context<Self>;
fn started(&mut self, ctx: &mut Context<Self>) {
println!("Actor is alive");
}
fn stopped(&mut self, ctx: &mut Context<Self>) {
println!("Actor is stopped");
}
}
/// Define handler for `Ping` message
impl Handler<Ping> for MyActor {
type Result = Result<bool, io::Error>;
fn handle(&mut self, msg: Ping, ctx: &mut Context<Self>) -> Self::Result {
println!("Ping received");
Ok(true)
}
}
fn main() {
let sys = System::new("example");
// Start MyActor in current thread
let addr = MyActor.start();
// Send Ping message.
// send() message returns Future object, that resolves to message result
let result = addr.send(Ping);
// spawn future to reactor
Arbiter::spawn(
result.map(|res| {
match res {
Ok(result) => println!("Got result: {}", result),
Err(err) => println!("Got error: {}", err),
}
System::current().stop();
})
.map_err(|e| {
println!("Actor is probably died: {}", e);
}));
sys.run();
}
通过Arbiter::spawn
来产生任务,其中Handler
来处理自定义的Actor和Msg。
自定义类型应答
extern crate actix;
extern crate futures;
use actix::dev::{MessageResponse, ResponseChannel};
use actix::prelude::*;
use futures::Future;
enum Messages {
Ping,
Pong,
}
enum Responses {
GotPing,
GotPong,
}
// 对于Response的相应处理,普通类型不需要,自定义类型需要
impl<A, M> MessageResponse<A, M> for Responses
where
A: Actor,
M: Message<Result=Responses>,
{
fn handle<R: ResponseChannel<M>>(self, _: &mut A::Context, tx: Option<R>) {
if let Some(tx) = tx {
tx.send(self);
}
}
}
impl Message for Messages {
type Result = Responses;
}
// Define actor
struct MyActor;
// Provide Actor implementation for our actor
impl Actor for MyActor {
type Context = Context<Self>;
fn started(&mut self, ctx: &mut Context<Self>) {
println!("Actor is alive");
}
fn stopped(&mut self, ctx: &mut Context<Self>) {
println!("Actor is stopped");
}
}
/// Define handler for `Messages` enum
impl Handler<Messages> for MyActor {
type Result = Responses;
fn handle(&mut self, msg: Messages, ctx: &mut Context<Self>) -> Self::Result {
match msg {
Messages::Ping => Responses::GotPing,
Messages::Pong => Responses::GotPong,
}
}
}
fn main() {
let sys = System::new("example");
// Start MyActor in current thread
let addr = MyActor.start();
// Send Ping message.
// send() message returns Future object, that resolves to message result
let ping_future = addr.send(Messages::Ping);
let pong_future = addr.send(Messages::Pong);
// Spawn pong_future onto event loop
Arbiter::spawn(
pong_future
.map(|res| {
match res {
Responses::GotPing => println!("Ping received"),
Responses::GotPong => println!("Pong received"),
}
System::current().stop();
})
.map_err(|e| {
println!("Actor is probably died: {}", e);
}),
);
// Spawn ping_future onto event loop
Arbiter::spawn(
ping_future
.map(|res| {
match res {
Responses::GotPing => println!("Ping received"),
Responses::GotPong => println!("Pong received"),
}
System::current().stop();
})
.map_err(|e| {
println!("Actor is probably died: {}", e);
}),
);
sys.run();
}