5

この質問の著者のように、私は Scala 2.10 の先物と約束でユーザーに見える約束の理由を理解しようとしています。

特に、SIP の例に戻ると、完全に欠陥があるわけではありません。

import scala.concurrent.{ future, promise }
val p = promise[T]
val f = p.future
val producer = future {
  val r = produceSomething()
  p success r
  continueDoingSomethingUnrelated()
}
val consumer = future {
  startDoingSomething()
  f onSuccess {
    case r => doSomethingWithResult()
  }
}

produceSomethingへの呼び出しで実行時例外が発生するケースを想像しています。promise と Producer-future は完全に切り離されているため、システムがハングし、consumer が成功または失敗で完了することはありません。

したがって、約束を使用する唯一の安全な方法には、次のようなものが必要です

val producer = future {
  try {
    val r.produceSomething()
    p success r
  } catch {
     case e: Throwable =>
       p failure e
       throw e  // ouch
  }
  continueDoingSomethingUnrelated()
}

これは明らかにエラーが発生しやすく、冗長です。

目に見えるプロミス タイプで確認できる唯一のケースfuture {}(不十分な場合) は、MAD の回答のコールバック フックの 1 つです。しかし、SIP の例は私には意味がありません。

4

3 に答える 3

7

これが、何かが防弾であることをすでに知っている場合を除き、めったに使用successしない理由です。failure防弾が必要な場合Tryは、次のとおりです。

val producer = future {
  p complete Try( produceSomething )
  continueDoingSomethingUnrelated()
}

エラーを再度スローする必要はないようです。約束への答えに詰め込むことで、すでに対処していますよね?(また、produceSomethingそれ自体がフューチャーを返す場合は、completeWith代わりに使用できることに注意してください。)

于 2013-01-15T23:05:40.430 に答える
4

コンビネーター

ライブラリにまだないPromise追加のコンビネータを構築するために使用できます。Future

このような他のコンビネータを作成できるようにするには、Promises が必要です。

コールバックを適応させる

Promiseコールバック ベースの API を ベースの API に適合させるために使用しFutureます。例えば:

def retrieveThing(key: String): Future[Thing] = {
  val p = Promise[Thing]()

  val callback = new Callback() {
    def receive(message: ThingMessage) {
      message.getPayload match {
        case t: Thing =>
          p success t        
        case err: SystemErrorPayload =>
          p failure new Exception(err.getMessage)
      }
    }
  }

  thingLoader.load(key, callback, timeout)
  p.future
}

同期装置

を使用してシンクロナイザーを構築しPromiseます。たとえば、コストのかかる操作に対してキャッシュされた値を返すか、それを計算しますが、同じキーに対して 2 回計算しないでください。

private val cache = new ConcurrentHashMap[String, Promise[T]]

def getEntry(key: String): Future[T] = {
  val newPromise = Promise[T]()
  val foundPromise = cache putIfAbsent (key, newPromise)

  if (foundPromise == null) {
    newPromise completeWith getExpensive(key)
    newPromise.future
  } else {
    foundPromise.future
  }
}
于 2013-01-16T00:28:13.717 に答える
1

Promise には、成功/失敗のシナリオを自動的に処理することでこの問題を解決する completeWith(f: Future) メソッドがあります。

promise.completeWith( future {
  r.produceSomething
})
于 2013-01-15T23:15:38.330 に答える