使Scala远程演员更稳定

时间:2010-11-02 16:01:53

标签: scala actor

我正在编写一个小测试程序来尝试使用我在Scala项目中需要的Remote Actors。

基本目标是编写一个服务器的测试应用程序,该服务器可以处理一堆客户端和可以同时发送多个消息的更重要的客户端(如ping,请求更新和用户引发的数据请求)< / p>

我想出的是: 简要概述:客户端启动3个不同的actor,这些actor再次启动具有不同偏移的while循环中的actor,以便模拟相当随机的消息。

import scala.actors.remote.RemoteActor
import scala.actors.remote.Node
import scala.actors.Actor

trait Request
trait Response

case object WhoAmI extends Request
case class YouAre(s:String) extends Response

case object Ping extends Request
case object Pong extends Response

case class PrintThis(s:String) extends Request
case object PrintingDone extends Response

object Server {
  def main(args: Array[String]) {
    val server = new Server
    server.start
  }
}

class Server extends Actor {
  RemoteActor.alive(12345)
  RemoteActor.register('server, this)
  var count:Int = 0

  def act() {
    while(true) {
      receive {
        case WhoAmI => {
          count += 1
          sender ! YouAre(count.toString)
        }
        case Ping => sender ! Pong
        case PrintThis(s) => {
          println(s)
          sender ! PrintingDone
        }
        case x => println("Got a bad request: " + x)

      }
    }
  }
}

object Act3 extends scala.actors.Actor {
  def act = {
    var i = 0
    Thread.sleep(900)
    while (i <= 12) {
      i += 1
      val a = new Printer
      a.start
      Thread.sleep(900)
    }
  }
}

class Printer extends scala.actors.Actor {
  def act = {
    val server = RemoteActor.select(Node("localhost",12345), 'server)
    server ! PrintThis("gagagagagagagagagagagagaga")
    receive {
      case PrintingDone => println("yeah I printed")
      case _            => println("got something bad from printing")
    }
  }
}

object Act2 extends scala.actors.Actor {
  def act = {
    var i = 0

    while (i < 10) {
      i+=1
      val a = new Pinger
      a.start
      Thread.sleep(700)
    }
  }
}

class Pinger extends scala.actors.Actor {
  def act = {
    val server = RemoteActor.select(Node("localhost",12345), 'server)
    server ! Ping
    receive {
      case Pong => println("so I pinged and it fits")
      case x    => println("something wrong with ping. Got " + x)
    }
  }
}

object Act extends scala.actors.Actor {
  def act = {
    var i = 0

    while(i < 10) {
      i+=1
      val a = new SayHi
      a.start()
      Thread.sleep(200)
    }

  }
}

class SayHi extends scala.actors.Actor {
  def act = {
    val server = RemoteActor.select(Node("localhost",12345), 'server)
    server ! "Hey!"
  }
}

object Client {
  def main(args: Array[String]) {
    Act.start()
    //Act2.start()
    Act3.start()
  }
}

问题在于事情并没有像我期望的那样顺利进行: 当我只启动一个客户演员时(通过评论其他人,就像我在Act2中对Client所做的那样)事情通常但并不总是顺利。如果我开始两个或更多演员,通常打印输出大量出现(意思是:没有任何事情一次发生,然后打印输出显得相当快)。客户端有时会终止,有时也不会终止。

这可能不是最大的问题,但它们足以让我感到非常不舒服。我在演员和远程演员上做了很多阅读,但我发现可用的信息相当缺乏。

尝试在适当的地方添加exit个陈述。但这没有帮助。

有人知道我做错了什么吗?这里有任何一般技巧吗?一些dos和donts?

2 个答案:

答案 0 :(得分:3)

我的猜测是你的问题源于使用receiveThread.sleep阻止你的演员的线程。阻塞操作会占用actor的线程池中的线程,这可能会阻止其他actor执行,直到将新线程添加到池中。 This question可能会提供一些额外的见解。

您可以使用looploopWhilereactreactWithin重写许多演员以使用非阻止操作。例如

import scala.actors.TIMEOUT

object Act extends scala.actors.Actor {
   def act = {
      var i = 0
      loopWhile(i < 10) {
         reactWithin(200) { case TIMEOUT =>
            i+=1
            val a = new SayHi
            a.start()
         }
      }
   }
}

当然,您可以通过编写自己的控件构造来消除一些样板:

def doWithin(msec: Long)(f: => Unit) = reactWithin(msec) { case TIMEOUT => f }
def repeat(times: Int)(f: => Unit) = {
   var i = 0
   loopWhile(i < times) {
      f
      i+=1
   }
}

这将允许你写

repeat(10) {
   doWithin(200) {
      (new SayHi).start
   }
}

答案 1 :(得分:1)

您可以尝试使用Akka actors framework http://akkasource.org/