Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 阿克卡演员-短信邻居_Scala_Akka_Actor - Fatal编程技术网

Scala 阿克卡演员-短信邻居

Scala 阿克卡演员-短信邻居,scala,akka,actor,Scala,Akka,Actor,假设我在同一个参与者系统中有四个参与者(1,2,3,4)。每个参与者只能与其未向其发送消息的邻居一起发送消息(即1只能向2和4发送消息。2和4也只能向3发送消息,因为其邻居1已发送消息)。当一个参与者从其两个邻居收到消息时,它会打印其名称并停止系统。我可以部分实现。但这里的问题是,两个参与者同时从其两个邻居收到消息并停止。例如,如果我在1开始进程,1发送消息到4和2,2到3和4到3,所以理论上3应该打印,但我得到2和3都打印。请建议可以做什么。下面是我的示例逻辑 object Main exte

假设我在同一个参与者系统中有四个参与者(1,2,3,4)。每个参与者只能与其未向其发送消息的邻居一起发送消息(即1只能向2和4发送消息。2和4也只能向3发送消息,因为其邻居1已发送消息)。当一个参与者从其两个邻居收到消息时,它会打印其名称并停止系统。我可以部分实现。但这里的问题是,两个参与者同时从其两个邻居收到消息并停止。例如,如果我在1开始进程,1发送消息到4和2,2到3和4到3,所以理论上3应该打印,但我得到2和3都打印。请建议可以做什么。下面是我的示例逻辑

object Main extends App {

  //creating a actor system
  val actorSystem = ActorSystem("System")
  //creating four actor instances with id as 1,2,3,4
  for (i <- 1 to 4) {
    actorSystem.actorOf(CircularActor.props(4), "" + i)
  }
  //initiating message to actor 1
  actorSystem.actorSelection(s"/user/1") ! "hello from x"
}


class CircularActor(n: Int) extends Actor {

  //variable to keep a track whether the actor received two meesages(i.e.from both neighbours)
  var noOfMessagesReceived = 0

  //generic method to send message using actorPath
  def messageNeighbour(path:String){
    context.actorSelection(path) ! "hello from x"
  }

  override def receive: Receive = {

    case "hello from x" =>
      noOfMessagesReceived += 1
      if (noOfMessagesReceived == 2) {
        println(s"The actor that received both messages is ${self.path.name}")
        context.system.terminate()
      }
      else {
        //Figures out id of sender
        val pathValue = sender().path.name
        //Gets its own name
        val ownId = self.path.name.toInt
        //Finds out the previous neighbor
        val prev = if (ownId - 1 == 0) n else ownId - 1
        //Finds next neighbour
        val next = if (ownId == n) 1 else ownId + 1

        //If the message is from deadletter, then this is the initiator actor
        if (pathValue == "deadLetters") {
          messageNeighbour(s"/user/$prev")
          messageNeighbour(s"/user/$next")
        }
        //If the message is from its next neighbour,send it to previous
        else if (pathValue.toInt == next) {
          //introducing random delay
          Thread.sleep(1 + Random.nextInt(100))
          messageNeighbour(s"/user/$prev")
        }
        //If none of above,then send it to previous.
        else {
          Thread.sleep(1 + Random.nextInt(100))
          messageNeighbour(s"/user/$next")
        }
  }
}

object CircularActor {

  def props(n: Int): Props = Props(new CircularActor(n))
}
objectmain扩展应用程序{
//创建参与者系统
val actorSystem=actorSystem(“系统”)
//创建id为1,2,3,4的四个参与者实例
为了
NoofMessageReceived+=1
if(noofMessageReceived==2){
println(s“接收这两条消息的参与者是${self.path.name}”)
context.system.terminate()
}
否则{
//找出发送者的id
val pathValue=sender().path.name
//得到它自己的名字
val ownId=self.path.name.toInt
//找出前一个邻居
val prev=if(ownId-1==0)n else ownId-1
//找到下一个邻居
val next=if(ownId==n)1 else ownId+1
//如果消息来自死信,则这是启动器参与者
如果(路径值==“死信”){
MessageNeighbor(s)/用户/user/$prev“
MessageNeighbor(s)/user/$next)
}
//如果消息来自下一个邻居,请将其发送到上一个邻居
else if(pathValue.toInt==next){
//引入随机延迟
线程睡眠(1+Random.nextInt(100))
MessageNeighbor(s)/用户/user/$prev“
}
//如果以上都没有,则将其发送到上一个。
否则{
线程睡眠(1+Random.nextInt(100))
MessageNeighbor(s)/user/$next)
}
}
}
对象循环器{
def道具(n:Int):道具=道具(新循环器(n))
}

问题似乎在于,您假设消息是按发送顺序处理的,但事实并非如此。消息传递是异步的,唯一的保证是,对于任何给定的参与者,消息都是按到达的顺序处理的没有定义不同的参与者

因此,在您的系统中,可以按此顺序处理消息

<dead> -> 1
     1 -> 2,4
     4 -> 3
     3 -> 2
     2 -> 3
     2 -> <terminate>
->1
1 -> 2,4
4 -> 3
3 -> 2
2 -> 3
2 -> 
如您所见,actor
2
在任何其他actor之前处理两条消息


我们不清楚可以做什么,因为我们不清楚您试图实现什么。但是,用这样的循环构建参与者系统是危险的。一般来说,参与者系统应该组织为请求树或DAG,并向请求参与者发送回复。

要实现所需的行为,我们需要参与者跟踪ac接收消息的目标

型号:

abstract class Direction

object Left extends Direction

object Right extends Direction

object StartPoint extends Direction

object Process
簿记员演员

class BookKeeperActor extends Actor {
var visitedActorRefs: mutable.HashSet[String] = mutable.HashSet.empty[String]

override def receive: Receive = {
  case Process =>
    if (visitedActorRefs.contains(sender().path.toString)) {
      context.stop(self)
      context.system.terminate()
      println(s"The actor that received both messages is ${sender().path.toString}")
    }
    else
      visitedActorRefs.add(sender().path.toString)
}

}
循环演员:

class CircularActor(n: Int, bookKeeper: ActorRef) extends Actor {


//generic method to send message using actorPath
def messageNeighbour(path: String, direction: Direction) {
  context.actorSelection(path) ! ("hello from x", direction)
}

override def receive: Receive = {


  case ("hello from x", direction: Direction) =>
    bookKeeper ! Process
    //Figures out id of sender
    val pathValue = sender().path.name
    //Gets its own name
    val ownId = self.path.name.toInt
    //Finds out the previous neighbor
    val prev = if (ownId - 1 == 0) n else ownId - 1
    //Finds next neighbour
    val next = if (ownId == n) 1 else ownId + 1

    Thread.sleep(1 + Random.nextInt(100))

    direction match {
      case StartPoint =>
        messageNeighbour(s"/user/$prev", Left)
        messageNeighbour(s"/user/$next", Right)
      case Left => messageNeighbour(s"/user/$prev", Left)
      case Right => messageNeighbour(s"/user/$next", Right)
    }

}

}


object CircularActor {

def props(n: Int, bookeeper: ActorRef): Props = Props(new CircularActor(n, bookeeper))
}
主应用程序-

object Main extends App {

val actorSystem = ActorSystem("System")
//creating four actor instances with id as 1,2,3,4
val bookKeeperActor = actorSystem.actorOf(Props(new BookKeeperActor))
for (i <- 1 to 4) {
  val ac = actorSystem.actorOf(CircularActor.props(4, bookKeeperActor), "" + i)
}
//initiating message to actor 1
actorSystem.actorSelection(s"/user/1") ! ("hello from x", StartPoint)
}
objectmain扩展应用程序{
val actorSystem=actorSystem(“系统”)
//创建id为1,2,3,4的四个参与者实例
val bookkeeparector=actorSystem.actorOf(道具(新bookkeeparector))

对于(我没有具体的用例。我只是想知道,谁是第一个从两个邻居那里收到消息的人。这可以实现吗?@SugaRaj你的代码确实可以做到这一点,但理论上可能是任何一个演员第一个收到两条消息。我不确定你为什么要打印两行,可能是因为演员太笨了。)调用
terminate()
时,stem不会立即关闭。我仍在试图找出控制台中的两条打印语句的原因。如果您有任何更改,请告诉我