并发之Actor模型


并行与并发

Erlang 之父 Joe Armstrong Erlang 之父 Joe Armstrong

  • 并发(concurrency) 并发的关注点在于任务切分。单核CPU也可以并发,只需要将不同的task按时间片切分。在没个时间段内就会有多个task被执行过。一些被阻塞的task也可以让出CPU时间片给其他task执行。
  • 并行(parallelism) 并行的关注点在于同时执行。多核CPU。可以将多个task同时执行。

我们代码里遇到的都是并发,并发是包含并行的。

Actor

Actor Model由Carl Hewitt在1973年提出,Gul Agha在1986年发表学术报告“Actors: A Model of Concurrent Computation in Distributed Systems”,至今已有不少年头了。在计算机科学中,它是一个并行计算的数学模型,最初为由大量独立的微处理器组成的高并行计算机所开发,Actor Model的理念非常简单:天下万物皆为Actor。

Actor Model是计算机科学领域并行计算的数学模型。An actor被看作并发的,通用的计算基元。Actors能够接受和发送消息、做出业务逻辑判断、创建更多的Actors并监管它们、决定在收到收到下一条消息时采用哪种行为。Actors之间只能通过消息修改自身私有状态(避免需要任何的锁)。

Akka Actor

  • Dispatcher
    Akka MessageDispatcher驱动Akka actor运行,也可以说是引擎。
    • Dispatcher
      • 可共享性: 无限制
      • 邮箱: 任何一种类型,为每一个Actor创建一个
      • 使用场景: 缺省派发器,Bulkheading
      • 底层使用: java.util.concurrent.ExecutorService
      • 可以指定“executor”使用“fork-join-executor”, “thread-pool-executor” 或者 the FQCN(类名的全称) of an akka.dispatcher.ExecutorServiceConfigurator
    • PinnedDispatcher
      • 可共享性: 无
      • 邮箱: 任何一种类型,为每个Actor创建一个
      • 使用场景: Bulkheading
      • 底层使用: 任何 akka.dispatch.ThreadPoolExecutorConfigurator
      • 缺省为一个 “thread-pool-executor”
    • BalancingDispatcher
      • 可共享性: 仅对同一类型的Actor共享
      • 邮箱: 任何,为所有的Actor创建一个
      • 使用场景: Work-sharing
      • 底层使用: java.util.concurrent.ExecutorService
      • 指定使用 “executor” 使用 “fork-join-executor”, “thread-pool-executor” 或 the FQCN(类名的全称) of an akka.dispatcher.ExecutorServiceConfigurator
    • CallingThreadDispatcher
      • 可共享性: 无限制
      • 邮箱: 任何,每Actor每线程创建一个(需要时)
      • 使用场景: 仅为测试使用
      • 底层使用: 调用的线程 (duh)
  • Emailbox
    保存发往某 Actor的消息. 通常每个 Actor 拥有自己的邮箱, 但是如果是使用 BalancingDispatcher 使用同一个 BalancingDispatcher 的所有Actor共享同一个邮箱实例.
    • UnboundedMailbox - 缺省邮箱
    • SingleConsumerOnlyUnboundedMailbox
    • BoundedMailbox
    • NonBlockingBoundedMailbox
    • UnboundedPriorityMailbox
    • BoundedPriorityMailbox
    • UnboundedStablePriorityMailbox
    • BoundedStablePriorityMailbox
    • UnboundedControlAwareMailbox
    • BoundedControlAwareMailbox

Actor转账示例

  • 状态(state):Actor中的状态指的是Actor对象的变量信息,状态由Actor自己管理,避免了并发环境下的锁和内存原子性等问题

  • 行为(Behavior):行为指定的是Actor中计算逻辑,通过Actor接收到消息来改变Actor的状态

  • 邮箱(mailBox):邮箱是Actor和Actor之间的通信桥梁,邮箱内部通过FIFO消息队列来存储发送方Actor消息,接受方Actor从邮箱队列中获取消息

package com.withyou.platform.demo;

import akka.actor.*;

/**
 * @author jeremy
 */
public class ActorCase {

    public static void main(String[] args) {
        ActorSystem system = ActorSystem.create("testActor");
        for (int i = 0; i < 1000; i++) {
            final ActorRef ref = system.actorOf(Props.create(StudentActor.class), "student" + i);
            System.out.println("Send message: " + i);
            ref.tell("No. " + i, ActorRef.noSender());
        }
    }
}

class StudentActor extends UntypedAbstractActor {

    @Override
    public void onReceive(Object message) throws Throwable, Throwable {
        System.out.println(message.toString() + " Received.");
        Thread.sleep(1500);
    }
}

Akka Actor应用之EventBus

package com.withyou.platform.demo;

import akka.actor.*;
import akka.event.japi.LookupEventBus;

public class EventBusCase {

    public static String TOPIC_1 = "apple";

    private static String TOPIC_2 = "orange";

    public static void main(String[] args) {
        EventBusCenter busCenter = new EventBusCenter();
        ActorSystem system = ActorSystem.apply("eventbus");
        ActorRef javaRef = system.actorOf(Props.create(JavaActor.class));
        ActorRef pythonRef = system.actorOf(Props.create(PythonActor.class));

        //Subscribe
        busCenter.subscribe(javaRef, TOPIC_1);
        busCenter.subscribe(pythonRef, TOPIC_1);


        //Publish
        busCenter.publish(new EventMsg(TOPIC_1, "hello world"));

        system.terminate();
    }
}

class EventMsg {
    public final String topic;
    public final Object payload;

    public EventMsg(String topic, Object payload) {
        this.topic = topic;
        this.payload = payload;
    }
}

class EventBusCenter extends LookupEventBus<EventMsg, ActorRef, String> {

    @Override
    public int mapSize() {
        return 128;
    }

    @Override
    public int compareSubscribers(ActorRef a, ActorRef b) {
        return a.compareTo(b);
    }

    @Override
    public String classify(EventMsg event) {
        return event.topic;
    }

    @Override
    public void publish(EventMsg event, ActorRef subscriber) {
        subscriber.tell(event.payload, Actor.noSender());
    }
}

class JavaActor extends UntypedAbstractActor {

    @Override
    public void onReceive(Object message) throws Throwable, Throwable {
        System.out.println("JavaActor " + message.toString());
    }
}

class PythonActor extends UntypedAbstractActor {

    @Override
    public void onReceive(Object message) throws Throwable, Throwable {
        System.out.println("PythonActor " + message.toString());
    }
}

What is Akka?

Akka是一个免费开源的软件工具包,使用Akka可以很容易的在JVM上构建高并发和分布式的应用程序。Akka 支持多种编程模型,但是着重于Actor Model并发模型。它的设计灵感来自于Erlang语言。

Akka的同时支持使用Java和Scala进行开发。但Akka是用Scala语言写出来的。在Scala2.10版本中,Akka取代了Scala原有的Actor Model的实现,被收录于Scala标准库中。

Akka实现了独特的混合模型

对并发/并行程序的简单的、高级别的抽象。
异步、非阻塞、高性能的事件驱动编程模型。
非常轻量的事件驱动处理(1G内存可容纳数百万个actors)。

容错性

使用“let-it-crash”语义的监控层次体系。
监控层次体系可以跨越多个JVM,从而提供真正的容错系统。
非常适合编写永不停机、自愈合的高容错系统。

持久性

actor接收到的消息可以选择性的被持久化,并在actor启动或重启的时候重放。这使得actor能够恢复其状态,
即使是在JVM崩溃或正在迁移到另外节点的情况下。

Akka的两种使用方式

库(lib)方式:在web应用中使用,放到 WEB-INF/lib 中或者作为一个普通的Jar包放进classpath。
以微内核的形式:可以将你的应用放进一个独立的内核。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值