并行与并发
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)
- Dispatcher
- Emailbox
保存发往某 Actor的消息. 通常每个 Actor 拥有自己的邮箱, 但是如果是使用 BalancingDispatcher 使用同一个 BalancingDispatcher 的所有Actor共享同一个邮箱实例.- UnboundedMailbox - 缺省邮箱
- SingleConsumerOnlyUnboundedMailbox
- BoundedMailbox
- NonBlockingBoundedMailbox
- UnboundedPriorityMailbox
- BoundedPriorityMailbox
- UnboundedStablePriorityMailbox
- BoundedStablePriorityMailbox
- UnboundedControlAwareMailbox
- BoundedControlAwareMailbox
-
状态(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。
以微内核的形式:可以将你的应用放进一个独立的内核。