Расширение абстрактных удаленных актеров и сопоставление с образцом (ClassLoading?) В Scala - PullRequest
1 голос
/ 26 декабря 2011

Я реализую некоторые абстрактные классы, которые расширяют Actor и предоставляют некоторую дополнительную функциональность [1].Тем не менее, сопоставление с образцом, кажется, не работает в операторах приема.Если я отправляю объект case Connect с клиента на сервер и на сервере выполняю сопоставление с шаблоном в виде:

println("Starting to receive, e.g. " + Connect.getClass.toString)
receive {
  case Connect => println("Got a connected message")
  case m => println("Got something weird: " + m + " of type " + m.getClass.toString)
}

, то получается

Starting to receive, e.g. class ConnectionTest$Connect$
Got something weird: Connect of type class ConnectionTest$Connect$
...

Входящее сообщение не распознается как объект Connect в сопоставлении с образцом, даже если getClass говорит, что это так.Еще одна странность: m имеет тот же хэш-код, что и Connect, и сериализуется с точно таким же ByteArray, используя ObjectOutputStream и writeObject, но не равен ему (используя ==).Я думаю, что classLoader как-то ведет себя неправильно, но я в растерянности.

Вот более полный пример того, что я пытаюсь написать:

import scala.actors.{Actor, OutputChannel}
import scala.actors.Actor._
import scala.actors.remote.RemoteActor
import scala.actors.remote.RemoteActor._
import scala.actors.remote.Node

abstract class ConnectionTest(masterNode: Node, port: Int) {

  trait Message
  case object Connect extends Message

  abstract class Master extends Actor {
    def act {
      RemoteActor.classLoader = getClass.getClassLoader
      alive(port)
      register('MasterProcess, self)

      while (true) {
        println("Starting to receive, e.g. " + Connect.getClass.toString)
        receive {
          case Connect => println("Got a connect message")
          case m => println("Got something weird: " + m + " of type " + m.getClass.toString)
        }
      }
    }
  }

  abstract class Worker extends Actor {
    def act {
      RemoteActor.classLoader = getClass.getClassLoader
      val master = select(masterNode, 'MasterProcess)
      link(master)
      master ! Connect
    }
  }
}

Вот пример использования:

object MyConnectionApp extends optional.Application {

  case class MyConTest(hostname: String, port: Int) extends ConnectionTest(Node(hostname, port), port) {
    case object MyMaster extends Master
    case object MyWorker extends Worker
  }

  def main(master: Boolean) = {
    if (master)
      MyConTest("localhost", 2552).MyMaster start
    else
      MyConTest("localhost", 2552).MyWorker start
  }
}

Когда я запускаю эту программу, вывод такой же, как указано выше.Сообщение Connect, полученное удаленно от MyWorker, не было распознано при сопоставлении с образцом в методе действия MyMaster.Даже если getClass.toString оценивает одно и то же на них, они как-то не совпадают.Как я могу это исправить?

[1] Более подробно: я реализую среду для определенного вида параллельных вычислений на большом количестве узлов.В более сложном случае мне бы хотелось заменить ConnectionTest на ParallelComputation[Data, Result], где Data и Result - параметры типа.Сообщение также будет включать в себя классы, которые зависят от этих параметров, например

case object Computed(x: Data, y: Result) extends Message

В идеале я хотел бы, чтобы решение, которое хорошо сочеталось с этим шаблоном проектирования.

1 Ответ

2 голосов
/ 26 декабря 2011

Я не проверял, но я думаю, что вы не должны помещать вашу черту Message и реализации (включая объект Connect) в класс ConnectionTest. Вы можете поместить их в объект-компаньон. Если вы поместите их в класс, для каждого экземпляра будет отдельный объект Connect, содержащий класс ConnectionTest (и что еще хуже в контексте сериализации, он имеет ссылку на этот экземпляр).

объекты Connect, принадлежащие разным экземплярам ConnectionTest, различны и не соответствуют друг другу.

...