这个代码量有点多,所以分为两篇文章在写
使用Actor对象实现ExecutionContext接口
分析:
ExecutionContext接口主要是接收一个Runnable对象,并执行这个Runnable对象,而且也能进行Shutdown service
package com.linewell.chapter8
import akka.actor.{Actor, Props}
import akka.event.Logging
import scala.concurrent.ExecutionContext
/** * Created by ctao on 15-12-16. */
object ExecutionContextTest extends App{
/** * 执行对象 * @param runnable runnable * @param tag 标签 */
case class Executor(runnable: Runnable,tag:String)
/** * 停止指令 */
case object ShutDown
class ExecutionContextActor extends Actor{
val logger = Logging(context.system,this)
val exec = ExecutionContext.global
override def receive: Receive = {
case Executor(runnable,tag) =>
logger.info(s"prepare execute $tag")
exec.execute(runnable)
logger.info(s"finished execute $tag")
case ShutDown => logger.info("shutdown")
context.system.terminate()
}
}
val execute = system.actorOf(Props[ExecutionContextActor])
for(i <- 1 to 10) execute ! Executor(getPrintRunnable(i),s"tag num: $i")
Thread sleep 1000
execute ! ShutDown
/** * * @param i i标签 * @return 一个Runnable对象,其实这里也可以用工厂做,或者用伴生对象做 */
def getPrintRunnable(i:Int) = new Runnable {
override def run(): Unit = println(s"execute println $i")
}
}
实现FailureDetector类,每隔interval变量设置的时间就向指定的actor对象发送Indentify消息,如果该actor无法在threshold规定的时间内回复ActorIdentity消息,则应该向其父actor发送failed消息
package com.linewell.chapter8
import akka.actor._
import akka.event.Logging
import akka.pattern._
import akka.util.Timeout
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
/** * Created by ctao on 15-12-17. */
object FailureDetectorTest extends App {
case class Failed(path: String)
case class Check(actorPath: String, interval: Long, threshold: Long)
case class Create(name: String)
class ChildActor extends Actor {
val logger = Logging(context.system, this)
override def receive: Receive = {
case str: String => logger.info("str")
case Identify(y) => Thread sleep 1000
sender() ! ActorIdentity(self.path.toString, Some(self))
}
override def unhandled(msg: Any) = {
logger.info(s"cannot handle message $msg in this state.")
}
}
class ParentActor extends Actor {
val logger = Logging(context.system, this)
override def receive: Actor.Receive = {
case Create(name) => context.actorOf(Props[ChildActor], name)
case Failed(x) => logger.info(s"child $x is die")
}
}
class FailureDetectorActor extends Actor {
override def receive: Actor.Receive = {
case Check(actorPath, interval, threshold) => while (true) {
implicit val timeout = Timeout(threshold.nanosecond)
pipe(context.actorSelection(actorPath) ? Identify(actorPath)) to sender()
Thread sleep interval
}
}
}
class Master extends Actor {
val failureDetectorActor = system.actorOf(Props[FailureDetectorActor], "failure")
val logger = Logging(context.system, this)
override def receive: Actor.Receive = {
case Check(actorRef, interval, threshold) => failureDetectorActor ! Check(actorRef, interval, threshold)
case ActorIdentity(path, Some(ref)) => logger.info(s"$ref is live ")
case ActorIdentity(path, None) => context.actorSelection(s"${findParent(path.toString)}") ! Failed(path.toString)
}
}
val master = system.actorOf(Props[Master], "master")
val parent = system.actorOf(Props[ParentActor], "parent")
parent ! Create("child1")
master ! Check("/user/parent/child1", 1000, 1)
def findParent(path:String) = path.substring(0,path.lastIndexOf("/"))
}
分布式hash是一种分布在多台计算机上的集合,一台计算机拥有该集合的部分数据称为分片,请用DistributedMap实现:
package com.linewell.chapter8
import akka.actor.{Actor, ActorRef, Props}
import akka.event.Logging
import akka.pattern._
import akka.util.Timeout
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.concurrent.duration._
import scala.util.{Failure, Success}
/** * Created by ctao on 15-12-18. */
object DistributedMapTest extends App {
case class Get[K <: Any](key: K)
case class SetValue[K <: Any, V <: Any](key: K, value: V)
class DistributeMap[K <: Any, V <: Any](shards: ActorRef*) {
implicit val timeout = Timeout(10.seconds)
def hash(k: K) = k.hashCode() % shards.size
def update(key: K, value: V): Future[Unit] = {
val f = shards(hash(key)) ? SetValue(key, value)
f.asInstanceOf[Future[Unit]]
}
def get(key: K): Future[Option[V]] = {
val f = shards(hash(key)) ? Get(key)
f.asInstanceOf[Future[Option[V]]]
}
}
class ShardActor[K <: Any, V <: Any] extends Actor {
val map = collection.mutable.Map[Any, Any]()
val logger = Logging(context.system, this)
override def receive: Receive = {
case SetValue(key, value) =>
logger.info(s"insert into map key $key,value $value path ${self.path}")
map += (key -> value)
case Get(key) =>
logger.info(s"get $key ,path ${self.path}")
sender() ! map.get(key)
}
}
val a = system.actorOf(Props[ShardActor[Int, String]], "a")
val b = system.actorOf(Props[ShardActor[Int, String]], "b")
val c = system.actorOf(Props[ShardActor[Int, String]], "c")
val dis = new DistributeMap[Int, String](a, b, c)
for (i <- 1 to 10) yield dis.update(i, i.toString)
val f = for (i <- 1 to 10) yield dis.get(i)
f.foreach(x => x.onComplete {
case Success(y) => println(s"get value ${y.get}")
case Failure(e) => println(e.getMessage)
})
Thread sleep 1000
system.terminate()
}