Rust实践:使用Tokio实现Actor系统

简介:

原文:Actors with Tokio

原文主要介绍了如何使用Tikio 而不是已有的Actor库(Actix)来实现Actor系统,在我之前的文章里也讲过Actor系统是什么C++ Actor并发模型框架 Actor Framework (CAF),介绍的是C++的Actor库,而本篇采用Rust的 Tikio库,关于Tikio库可以查看何为Tikio,在实现Actor并发模型时,主要使用到Tikio的异步特性。

实现

首先,我们实现一个获取当前Id值的Actor


use tokio::sync::{oneshot, mpsc};
struct MyActor {
    receiver: mpsc::Receiver<ActorMessage>,
    next_id: u32,
}
enum ActorMessage {
    GetUniqueId {
        respond_to: oneshot::Sender<u32>,
    },
}
impl MyActor {
    fn new(receiver: mpsc::Receiver<ActorMessage>) -> Self {
        MyActor {
            receiver,
            next_id: 0,
        }
    }
    fn handle_message(&mut self, msg: ActorMessage) {
        match msg {
            ActorMessage::GetUniqueId { respond_to } => {
                self.next_id += 1;
                // The `let _ =` ignores any errors when sending.
                // `let _ =` 忽略了发送的任何 error
                // This can happen if the `select!` macro is used
                // to cancel waiting for the response.
                // 当 `select!` 宏被用到时将会停止接受响应
                let _ = respond_to.send(self.next_id);
            },
        }
    }
}
async fn run_my_actor(mut actor: MyActor) {
    while let Some(msg) = actor.receiver.recv().await {
        actor.handle_message(msg);
    }
}

有了Actor之后,该有消息投递方

#[derive(Clone)]
pub struct MyActorHandle {
    sender: mpsc::Sender<ActorMessage>,
}

impl MyActorHandle {
    pub fn new() -> Self {
    	//channel大小为8,即当消息数达到8个未消费时进行阻塞
        let (sender, receiver) = mpsc::channel(8);
        //构建一个处理消息队列接收端的Actor
        let actor = MyActor::new(receiver);
        //交给Tikio托管,注意 fun_my_actor未async关键字定义的函数
        tokio::spawn(run_my_actor(actor));
        // 译者提醒: 注意 tokio::spawn 的位置
        Self { sender }
    }

    pub async fn get_unique_id(&self) -> u32 {
        let (send, recv) = oneshot::channel();
        //发送获取id的消息
        let msg = ActorMessage::GetUniqueId {
            respond_to: send,
        };

        // Ignore send errors. If this send fails, so does the
        // recv.await below. There's no reason to check for the
        // same failure twice.
        // 忽略发送 error 。如果它发送失败, 将会执行下方的 recv.await
        // 检测同样的错误两次是没有道理的。
        let _ = self.sender.send(msg).await;
        recv.await.expect("Actor task has been killed")
    }
}

MyActorHandle相当于我们的主任务线程,比如从net io获取到消息时,可以将消息再丢入不同的actor进行处理。

你可能感兴趣的:(Rust,每周入门实践)