3

futures (scala.actors.Futures) 内でサブジョブを処理する単純なジョブ プロセッサを実装しました。これらの先物自体は、サブジョブを処理するためのより多くの先物を作成できます。ここで、これらのサブジョブの 1 つが例外をスローした場合、ジョブ プロセッサがそのジョブのエラー メッセージで応答するようにします。失敗したサブジョブを発見するための回避策がありますが、それが最善の解決策かどうかはわかりません。基本的には次のように機能します。

sealed trait JobResult
case class SuccessResult(content: String) extends JobResult
case class FailedResult(message: String) extends JobResult

for(subjob <- subjobs) yield {
  future {
    try {
          SuccessResult(process(subjob))
    } catch {
      case e:Exception => FailedResult(e.getMessage)                              
    }
  }
}

最上位の結果は、再帰的な Lists of Lists... of JobResults のリストです。リストで失敗した結果を再帰的に検索し、結果の種類に応じてエラーまたは結合された結果を返します。それは機能しますが、先物で例外を処理するためのよりエレガントで簡単なソリューションがあるかどうか疑問に思っていますか?

4

2 に答える 2

5

あなたが今それをする方法は、本質的にscala.Eitherのために設計されたものです。http://www.scala-lang.org/api/current/scala/Either.htmlを参照してください

于 2011-04-19T14:03:44.780 に答える
2

現代の scala の先物Either成功した結果またはThrowable. scala 2.10 でこのコードを再度参照すると、状況が非常に快適であることがわかると思います。

具体的には、scala.concurrent.Future[T]技術的には "is-a" のみですAwaitable[T]_.onCompleteAwait.ready(_, timeout).value.getどちらもその結果をscala.util.Try[T]Either[Throwable, T]として提示します。これは、結果または例外のいずれかであるという点でよく似ています。

奇妙なことに、_.transform2 つのマッピング関数を使用T => UThrowable => ThrowableますTry[T] => Try[U]Futureは、マッピング関数で例外をスローするだけで成功を失敗に変えることができますが、元の.mapの成功に対してのみそれを使用しFutureます。その.recover, 同様に失敗を成功に変えることができます. 成功を失敗に、またはその逆に変更できるようにしたい場合は、次のように新しいscala.concurrent.Promise[U]にチェーンするために使用するか_.map_.recoverまたは組み合わせたものを自分で作成する必要があります。_.onComplete

import scala.util.{Try, Success, Failure}
import scala.concurrent.{Future, Promise}
import scala.concurrent.ExecutionContext

def flexibleTransform[T,U](fut: Future[T])(f: Try[T] => Try[U])(implicit ec: ExecutionContext): Future[U] = {
  val p = Promise[U]
  fut.onComplete { res =>
    val transformed = f(res)
    p.complete(transformed)
  }
  p.future
}

次のように使用されます。

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration.Duration.Inf

def doIt() {
  val a: Future[Integer] = Future {
    val r = scala.util.Random.nextInt
    if (r % 2 == 0) {
      throw new Exception("we don't like even numbers")
    } else if (r % 3 == 0) {
      throw new Exception("we don't like multiples of three")
    } else {
      r
    }
  }

  val b: Future[String] = flexibleTransform(a) {
    case Success(i) =>
      if (i < 0) {
        // turn negative successes into failures
        Failure(new Exception("we don't like negative numbers"))
      } else {
        Success(i.toString)
      }
    case Failure(ex) =>
      if (ex.getMessage.contains("three")) {
        // nevermind about multiples of three being a problem; just make them all a word.
        Success("three")
      } else {
        Failure(ex)
      }
  }

  val msg = try {
    "success: " + Await.result(b, Inf)
  } catch {
    case t: Throwable =>
      "failure: " + t
  }
  println(msg)
}

for { _ <- 1 to 10 } doIt()

次のようなものが得られます。

failure: java.lang.Exception: we don't like even numbers
failure: java.lang.Exception: we don't like negative numbers
failure: java.lang.Exception: we don't like negative numbers
success: three
success: 1756800103
failure: java.lang.Exception: we don't like even numbers
success: 1869926843
success: three
failure: java.lang.Exception: we don't like even numbers
success: three

(または、暗黙的な def を使用して a に「pimp」Futureし、そのメンバー関数を作成して、パラメーターをドロップし、単に を使用することもできます)RichFutureWithFlexibleTransformflexibleTransformfutthis

(変換で非同期処理を実行できるように、それを取得Try[T] => Future[U]して呼び出すことをお勧めします)flexibleFlatMap

于 2014-03-16T18:34:45.183 に答える