2016-10-21 2 views
0

Я делаю свое небольшое исследование, которое реализует Актера без Akka Я нашел одну реализацию Актера в Скале. (How to implement actor model without Akka?)Реализовать актерскую модель без Akka в Scala

Это очень просто. Потому что у меня недостаточно репутации, чтобы добавить комментарий, поэтому я создаю этот вопрос. Интересно, использую ли я актера, как показано ниже.

1/Как я могу закрыть этот актер из основного потока?

2/Как добавить функцию, похожую на Akka, как родительский актер, убить запрос и стать методом?

import scala.concurrent._ 

trait Actor[T] { 
     implicit val context = ExecutionContext.fromExecutor(java.util.concurrent.Executors.newFixedThreadPool(1)) 
     def receive: T => Unit 
     def !(m: T) = Future { receive(m) } 
} 

Это мой собственный пример при попытке адаптировать приведенный выше кусок кода

import scala.concurrent._ 

/** 
    * Created by hminle on 10/21/2016. 
    */ 
trait Message 
case class HelloMessage(hello: String) extends Message 
case class GoodByeMessage(goodBye: String) extends Message 

object State extends Enumeration { 
    type State = Value 
    val Waiting, Running, Terminating = Value 
} 

trait Actor[T] { 
    implicit val context = ExecutionContext.fromExecutor(java.util.concurrent.Executors.newFixedThreadPool(1)) 
    private var state: State.State = State.Waiting 
    def handleMessage: T => Unit ={ 
    if(state == State.Waiting) handleMessageWhenWaiting 
    else if(state == State.Running) handleMessageWhenRunning 
    else handleMessageWhenTerminating 
    } 
    def !(m: T) = Future {handleMessage(m)} 
    def handleMessageWhenWaiting: T => Unit 
    def handleMessageWhenRunning: T => Unit 
    def handleMessageWhenTerminating: T => Unit 
    def transitionTo(destinationState: State.State): Unit = { 
    this.state = destinationState 
    } 
} 

class Component1 extends Actor[Message]{ 
    def handleMessageWhenRunning = { 
    case HelloMessage(hello) => { 
     println(Thread.currentThread().getName + hello) 
    } 
    case GoodByeMessage(goodBye) => { 
     println(Thread.currentThread().getName + goodBye) 
     transitionTo(State.Terminating) 
    } 
    } 

    def handleMessageWhenWaiting = { 
    case m => { 
     println(Thread.currentThread().getName + " I am waiting, I am not ready to run") 
     transitionTo(State.Running) 
    } 
    } 

    def handleMessageWhenTerminating = { 
    case m => { 
     println(Thread.currentThread().getName + " I am terminating, I cannot handle any message") 
     //need to shutdown here 
    } 
    } 

} 
class Component2(component1: Actor[Message]) extends Actor[Message]{ 
    def handleMessageWhenRunning = { 
    case HelloMessage(hello) => { 
     println(Thread.currentThread().getName + hello) 
     component1 ! HelloMessage("hello 1") 
    } 
    case GoodByeMessage(goodBye) => { 
     println(Thread.currentThread().getName + goodBye) 
     component1 ! GoodByeMessage("goodbye 1") 
     transitionTo(State.Terminating) 
    } 
    } 

    def handleMessageWhenWaiting = { 
    case m => { 
     println(Thread.currentThread().getName + " I am waiting, I am not ready to run") 
     transitionTo(State.Running) 
    } 
    } 

    def handleMessageWhenTerminating = { 
    case m => { 
     println(Thread.currentThread().getName + " I am terminating, I cannot handle any message") 
     //need to shutdown here 
    } 
    } 
} 
object ActorExample extends App { 
    val a = new Component1 
    val b = new Component2(a) 
    b ! HelloMessage("hello World 2") 
    b ! HelloMessage("hello World 2, 2nd") 
    b ! GoodByeMessage("Good bye 2") 
    println(Thread.currentThread().getName) 
} 

ответ

0

Вы можете посмотреть на Actor model реализации в scalaz и принимать идеи от него, исходный код в scalaz actor проще для понимания, чем akka. У вас есть свобода выбора архитектуры: вы можете использовать почтовые ящики на основе ConcurrentLinkedQueue, например, в Akka, использовать CAS для AtomicReffernce, как в scalaz, в вашем случае вы используете механизм Future. ИМО, вы должны написать контекст вашей системы актера, поэтому решить первые и вторые элементы в вашем вопросе это вариант ActorContext:

val contextStack = new ThreadLocal[List[ActorContext]] 

и выключение может выглядеть следующим образом:

1.

case Kill      ⇒ throw new ActorKilledException("Kill") 
case PoisonPill     ⇒ self.stop() 

2. Для хранения родительского актера и подобную задачу, вы должны хранить ссылки на них:

def parent: ActorRef 

трудно сказать о преимуществах каждой техники (CAS, почтовые ящики), это возможные варианты для ваших исследований.

Смежные вопросы