Сделайте Scala Remote Actors более стабильным - PullRequest
4 голосов
/ 02 ноября 2010

Я писал небольшую тестовую программу, чтобы опробовать некоторые вещи с удаленными актерами, которые мне понадобятся в проекте Scala.

Основная цель состояла в том, чтобы написать тестовое приложение для одного сервера, которое могло бы обрабатывать группу клиентов и более важных клиентов, которые могут отправлять несколько сообщений одновременно (например, пинги, запросы на обновления и запросы пользователей на данные)

Я придумал вот что: краткий обзор: клиент запускает 3 разных актера, которые снова запускают актеров в циклах while с разными смещениями для имитации довольно случайных сообщений.

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 операторов там, где это казалось подходящим. Но это не помогло.

Кто-нибудь понял, что я делаю не так? Есть какие-нибудь общие хитрости здесь? Какие-нибудь плюсы и минусы?

Ответы [ 2 ]

3 голосов
/ 03 ноября 2010

Я предполагаю, что ваши проблемы связаны с блокировкой потоков вашего актера с помощью receive и Thread.sleep.Блокирующие операции потребляют потоки в пуле потоков участников, что может препятствовать выполнению другими участниками, пока новые потоки не будут добавлены в пул. Этот вопрос может дать некоторую дополнительную информацию.

Вы можете использовать loop, loopWhile, react и reactWithin, чтобы переписать многих ваших актеров для использования неблокирующихоперации.Например,

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 голос
/ 02 ноября 2010

Вместо этого вы можете попробовать рамки актеров Akka http://akkasource.org/

...