4

node.js のバックグラウンドを持つ私は Scala を初めて使用し、Twitter の Future.collect を使用していくつかの単純な同時操作を実行しようとしました。しかし、私のコードは、同時動作ではなく順次動作を示しています。私は何を間違っていますか?

ここに私のコードがあります、

import com.twitter.util.Future

def waitForSeconds(seconds: Int, container:String): Future[String]  = Future[String] {
  Thread.sleep(seconds*1000)
  println(container + ": done waiting for " + seconds + " seconds")
  container + " :done waiting for " + seconds + " seconds"
}

def mainFunction:String = {
  val allTasks = Future.collect(Seq(waitForSeconds(1, "All"), waitForSeconds(3, "All"), waitForSeconds(2, "All")))
  val singleTask = waitForSeconds(1, "Single")

  allTasks onSuccess  { res =>
    println("All tasks succeeded with result " + res)
  }

  singleTask onSuccess { res =>
    println("Single task succeeded with result " + res)
  }

  "Function Complete"
}

println(mainFunction)

これは私が得る出力です、

All: done waiting for 1 seconds
All: done waiting for 3 seconds
All: done waiting for 2 seconds
Single: done waiting for 1 seconds
All tasks succeeded with result ArraySeq(All :done waiting for 1 seconds, All :done waiting for 3 seconds, All :done waiting for 2 seconds)
Single task succeeded with result Single :done waiting for 1 seconds
Function Complete

私が期待する出力は、

All: done waiting for 1 seconds
Single: done waiting for 1 seconds
All: done waiting for 2 seconds
All: done waiting for 3 seconds
All tasks succeeded with result ArraySeq(All :done waiting for 1 seconds, All :done waiting for 3 seconds, All :done waiting for 2 seconds)
Single task succeeded with result Single :done waiting for 1 seconds
Function Complete
4

1 に答える 1

8

Twitter のフューチャーは、Scala 標準ライブラリーのフューチャーよりも計算が実行される場所についてより明示的です。特に、Future.apply( のように) 例外を安全にキャプチャs.c.Futureしますが、計算が実行されるスレッドについては何も述べていません。あなたの場合、計算はメイン スレッドで実行されているため、結果が表示されます。見ています。

このアプローチには、標準ライブラリの将来の API よりもいくつかの利点があります。ExecutionContext1 つには、どこにでも渡さなければならない暗黙的なものがないため、メソッド シグネチャがよりシンプルに保たれます。さらに重要なことは、コンテキストの切り替えを簡単に回避できることです (これは、Brian Degenhardt による古典的な説明です)。この点では、TwitterFutureは Scalaz に似Taskており、本質的に同じパフォーマンス上の利点があります (たとえば、このブログ投稿で説明されています)。

計算が実行される場所をより明確にすることの欠点は、計算が実行される場所をより明確にする必要があることです。あなたの場合、次のように書くことができます:

import com.twitter.util.{ Future, FuturePool }

val pool = FuturePool.unboundedPool

def waitForSeconds(seconds: Int, container:String): Future[String] = pool {
  Thread.sleep(seconds*1000)
  println(container + ": done waiting for " + seconds + " seconds")
  container + " :done waiting for " + seconds + " seconds"
}

これは、あなたが求めている正確な出力を生成しません (「関数の完了」が最初に出力され、相互に順序付けされません) が、別々のスレッドでタスクを並行して実行しますallTaskssingleTask

(脚注:FuturePool.unboundedPool上記の私の例では、デモ用の将来のプールを作成する簡単な方法であり、多くの場合は問題ありませんが、CPU を集中的に使用する計算には適していません。作成する他の方法については、FuturePoolAPI ドキュメントを参照してください。あなたが提供し、自分で管理できるを使用する将来のプールですExecutorService。)

于 2016-12-02T14:33:25.233 に答える