10

Java では、マルチスレッド環境で必要な共有リソースにアクセスするメソッドまたはブロックを同期します。

これを行う「Scala Actors」の方法がどのように機能するのか疑問に思っています。

java.sql.Connectionスレッドセーフなアクセスを提供したいオブジェクトの接続プールがあるとします。メッセージを受信し、送信者に接続を返すアクターとして実装します。

これを行うには、次の 3 つの方法があるようです。

  1. 未来を使う
  2. 使用する!?
  3. 必要なクラスをConnectionアクターにする

コード:

sealed abstract class ConnectionPoolMessage
case class NewConnection extends ConnectionPoolMessage
case class CloseConnection(c:Connection) extends ConnectionPoolMessage

class ConnectionPool extends Actor {
  def act() {
    while (true) {
      receive() {
        case NewConnection => sender ! getConnectionFromPool
        case CloseConnection(conn) => returnConnection(conn)
      }
    }
  }
}

// Here, my "do stuff" method is all in one place, and I block waiting
// on the Future from the pool; however this could take forever and cause trouble
class UsingFuture {
  val pool = new ConnectionPool
  def doSomething() {
    val connectionFuture = pool !! NewConnection
    val connection = connectionFuture() // concerned that we can't timeout here
    // do stuff with my Connection instance
    pool ! CloseConnection(connection)  
  }
}


// here, I wait and just use a timeout
// Seems clean to me, I guess.
class UsingBangQuestion {
  val pool = new ConnectionPool
  def doSomething() {
    pool !?(TIMEOUT,NewConnection) match {
      case Some(conn) => {
        // do something with connection
        pool ! CloseConnection(conn)
      }
      case None => throw new RuntimeException("timed out")
    }
  }
}

// here, I don't worry about timeouts, cause I only use the
// the connection when I receive a message back with it.  
// The problem is that I now have to split my logic up
// with two methods
class AsAnActor extends Actor {
  val pool = new ConnectionPool
  def startSomething() {
    start
    pool ! NewConnection
  }
  def act() {
    receive() {
      case conn:Connection => finishSomething(conn)
    }
  }
  def finishSomething(conn:Connection) {
    // do stuff with my Connection
    pool ! CloseConnection(conn)
  }
}

永久にブロックできるという事実を除けば、Future バージョンが最もクリーンに見えます。

何か考えがありますか、それとも私の考え全体が間違っていますか?

4

3 に答える 3

2

悪いスタイルかもしれませんが、1 つの方法は、(接続が必要な) アクターに接続プールを直接接続させ、同期を使用してConnection. 正直なところ、このアプローチのどこが悪いのか、私にはよくわかりません。私はデッドロック(またはライブロック)を叫ぶだけの!!またはよりもはるかに好きです!!?

もう1つの方法は、接続で実行する必要がある作業と結果の可能なターゲットを表すメッセージをプールに送信することだと思います。

class DbWork(f: Connection => Unit)
class DbWorkWithResult[T](f:Connection => T, target: OutputChannel[Any])

そして、次のように使用できます。

pool ! new DbWork( { (conn: Connection) => //do something 
                 })

または:

pool ! new DbWorkWithResult[Int]( (conn: Connection) => //return int
                 }, self)
于 2009-10-29T19:49:44.107 に答える
0

それを行うアクターの方法は、リソースを共有することではありません。共有リソースへのアクセスを処理するジョブを持つ単一のアクタにすべてのアクセス権を与えます。

このように、リソース自体はスレッド間で共有されません。アクターは。

于 2009-10-29T21:07:06.930 に答える
0

Scala アクターから非アクターへの対話 (またはアクターからサーブレットへのメッセージの同期) への回答に見られるように、!?(timeout, message) を使用して Some(answer) またはタイムアウトの場合は None を受け取ることができます。

于 2011-01-11T10:00:49.957 に答える