Actix

  • 并发:同一时间有多个可以执行的进程,单核和多核都可并发,单核并发的本质是轮流使用。
  • 并行:同一时间多个进程在微观上都在真正的执行,需要有多核或多主机才能并行计算。
  • 分布式:一个业务分拆多个子业务,部署在多个服务器上,不同的服务器节点完成不同的任务。
  • 集群:同一个业务部署在多台机器上,提高系统可用性,相当于不同的服务器对外提供一致的服务。

并发与并行

数据通信的两种策略

  1. 共享数据(需要加锁

  2. 传递消息

传递消息的两种形式

  1. 基于 Channel 的消息传递(消息队列

  2. 基于 Actor 模型的消息传递

Actor 的三个组成部分:

  • 状态(State):Actor 之间不共享数据,各自管理自己的状态。
  • 行为(Behavior):Actor 中的计算逻辑,根据接收到的消息来改变 Actor 的状态。
  • 邮箱(MailBox):Actor 之间只能以消息方式交互,通过 FIFO(先入先出)队列来存储接收到的消息。

Actor 的创建和调度的效率高。

Actor 模型更接近现实世界,现实世界也是分布式的、异步的、基于消息的、尤其 Actor 对于异常(失败)的处理、自愈、监控等都更符合现实世界的逻辑。

Actor Model

An actor is allowed to do several things, including:

  • receive message and send a response
  • send messages to other actors
  • change its own state

The “actor model” is the main primitive that powers the Erlang programming language and its descendant, Elixir.

 

It describes a programming model that simplifies the development of concurrent and multi-threaded applications or even distributed applications.

class CounterActor {
  constructor() {
    this.count = 0;
  }

  onReceive(message) {
    if (message.type === 'plus-one') {
      this.count += 1;
    }

    return this.count;
  }
}

A simplified example in JavaScript

actix

The complexity of actors is relatively low, and that is because the complexity is usually hidden in the actor frameworks that are used to run these types of primitives in the end.

actix is the low-level actor framework that powers actix-web, a high-performance web framework for the Rust programming language.

pub trait Actor {
    // Actor execution context type
    type Context: ActorContext;

    // Start new asynchronous actor, returns address of newly created actor.
    fn start(self) -> Addr<Self>
        where Self: Actor<Context = Context<Self>> { ... }

    // lifecycle events
    fn started(&mut self, ctx: &mut Self::Context) { ... }
    fn stopping(&mut self, ctx: &mut Self::Context) -> Running { ... }
    fn stopped(&mut self, ctx: &mut Self::Context) { ... }
}

pub trait ActorContext {
    // Actor execution state
    fn state(&self) -> ActorState;

    // Initiate stop process and switch to a stopping state
    fn stop(&mut self);

    // Terminate actor execution and switch to stopped state
    fn terminate(&mut self);
}

pub struct Context<A> where A: Actor<Context = Context<A>> { ... }

impl<A> ActorContext for Context<A> where A: Actor<Context = Self> { ... }

pub enum ActorState {
    Started,
    Running,
    Stopping,
    Stopped,
}

pub trait Message {
    // The type of value that this message will resolved with
    // if it is successful.
    type Result: 'static;
}

pub trait Handler<M> 
where
    Self: Actor,
    M: Message, 
{
    type Result: MessageResponse<Self, M>;

    // Method is called for every message received by this Actor
    fn handle(&mut self, msg: M, ctx: &mut Self::Context) -> Self::Result;
}
use actix::prelude::*;

// `PlusOne` message implementation
struct PlusOne;

impl Message for PlusOne {
    type Result = u32;
}

// `CounterActor` implementation
struct CounterActor {
    count: u32,
}

impl CounterActor {
    pub fn new() -> CounterActor {
        CounterActor { count: 0 }
    }
}

impl Actor for CounterActor {
    type Context = Context<Self>;
}

impl Handler<PlusOne> for CounterActor {
    type Result = u32;

    fn handle(&mut self, _msg: PlusOne, _ctx: &mut Context<Self>) -> u32 {
        self.count += 1;
        self.count
    }
}

CounterActor example in Rust

Made with Slides.com