50,000個のタスクがあり、それらを10個のスレッドで実行したい。 Java Executers.threadPool(10)を作成し、runnableを渡してから、すべてを処理するのを待つ必要があります。Scalaしかし、ドキュメントで解決策を見つけることができません。
最も簡単なアプローチは、scala.concurrent.Future
クラスと関連インフラストラクチャを使用することです。 scala.concurrent.future
メソッドは、渡されたブロックを非同期的に評価し、非同期計算を表すFuture[A]
をすぐに返します。先物は、マッピング、flatMapping、フィルタリング、エラーの回復などを含む、多くの非ブロッキング方法で操作できます。
たとえば、10個のタスクを作成するサンプルは次のとおりです。各タスクは任意の時間だけスリープし、渡された値の2乗を返します。
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
val tasks: Seq[Future[Int]] = for (i <- 1 to 10) yield future {
println("Executing task " + i)
Thread.sleep(i * 1000L)
i * i
}
val aggregated: Future[Seq[Int]] = Future.sequence(tasks)
val squares: Seq[Int] = Await.result(aggregated, 15.seconds)
println("Squares: " + squares)
この例では、最初に一連の個々の非同期タスクを作成し、完了したらintを提供します。次に、Future.sequence
を使用して、これらの非同期タスクを単一の非同期タスクに結合します。つまり、型のFuture
とSeq
の位置を交換します。最後に、結果を待つ間、現在のスレッドを最大15秒間ブロックします。この例では、グローバル実行コンテキストを使用します。このコンテキストは、fork/joinスレッドプールによってサポートされています。自明ではない例については、おそらくアプリケーション固有のExecutionContext
を使用する必要があります。
一般に、ブロッキングは可能な限り回避する必要があります。 Future
、onSuccess
、onFailure
など、非同期スタイルでのプログラミングに役立つ他のコンビネーターがonComplete
クラスで使用できます。
また、 Akka ライブラリの調査を検討してください。このライブラリは、ScalaおよびJava、およびscala.concurrent
と相互運用するアクターベースの並行性を提供します。
この最も簡単なアプローチは、ActorsフレームワークのサブコンポーネントであるScalaのFutureクラスを使用することです。 scala.actors.Futures.futureメソッドは、渡されたブロックのFutureを作成します。その後、scala.actors.Futures.awaitAllを使用して、すべてのタスクが完了するまで待機できます。
たとえば、10個のタスクを作成するサンプルは次のとおりです。各タスクは任意の時間だけスリープし、渡された値の2乗を返します。
import scala.actors.Futures._
val tasks = for (i <- 1 to 10) yield future {
println("Executing task " + i)
Thread.sleep(i * 1000L)
i * i
}
val squares = awaitAll(20000L, tasks: _*)
println("Squares: " + squares)
Scala actors libraryまたはAkka。
したがって、タスクの処理方法を知っているアクターのプールを作成する必要があるようです。アクターは基本的に、Akkaチュートリアル( http://doc.akkasource.org/tutorial-chat-server-scala )のreceiveメソッドを持つ任意のクラスになります:
class MyActor extends Actor {
def receive = {
case "test" => println("received test")
case _ => println("received unknown message")
}}
val myActor = Actor.actorOf[MyActor]
myActor.start
アクターインスタンスのプールを作成し、タスクをメッセージとして実行する必要があります。 Akkaアクタープーリングに関する役立つ投稿を次に示します。 http://vasilrem.com/blog/software-development/flexible-load-balancing-with-akka-in-scala/
あなたの場合、タスクごとに1つのアクターが適切な場合があります(アクターはスレッドと比較して非常に軽量であるため、単一のVMでそれらのLOTを使用できます)か、より高度な負荷分散が必要になる場合があります。
編集:上記のサンプルアクターを使用して、メッセージを送信するのは次のように簡単です。
myActor ! "test"
次に、アクターは「受信したテスト」を標準出力に出力します。
メッセージはどのようなタイプでもかまいません。Scalaのパターンマッチングと組み合わせると、柔軟な同時アプリケーションを構築するための強力なパターンが得られます。
一般に、Akkaアクターはスレッド共有の観点から「正しいことをする」でしょう。OPのニーズのために、デフォルトは問題ないと思います。ただし、必要に応じて、アクターが使用するディスパッチャをいくつかのタイプのいずれかに設定できます。
* Thread-based
* Event-based
* Work-stealing
* HawtDispatch-based event-driven
アクターにディスパッチャを設定するのは簡単です:
class MyActor extends Actor {
self.dispatcher = Dispatchers.newExecutorBasedEventDrivenDispatcher("thread-pool-dispatch")
.withNewThreadPoolWithBoundedBlockingQueue(100)
.setCorePoolSize(10)
.setMaxPoolSize(10)
.setKeepAliveTimeInMillis(10000)
.build
}
http://doc.akkasource.org/dispatchers-scala を参照してください
この方法で、スレッドプールのサイズを制限できますが、再び、元のユースケースは、おそらくデフォルトのディスパッチャーを使用する50K Akkaアクターインスタンスで満足でき、うまく並列化できます。
これは、実際にAkkaができることのほんの一部に過ぎません。 ErlangがScala言語に提供するものの多くをもたらします。アクターは他のアクターをモニターして再起動し、自己修復アプリケーションを作成できます。Akkaはソフトウェアトランザクションメモリおよび他の多くの機能も提供します。 Scalaの「キラーアプリ」または「キラーフレームワーク」。
Mpilquistの応答に似ていますが、非推奨のAPIがなく、カスタムExecutionContextを介したスレッド設定を含む別の回答があります。
import Java.util.concurrent.Executors
import scala.concurrent.{ExecutionContext, Await, Future}
import scala.concurrent.duration._
val numJobs = 50000
var numThreads = 10
// customize the execution context to use the specified number of threads
implicit val ec = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(numThreads))
// define the tasks
val tasks = for (i <- 1 to numJobs) yield Future {
// do something more fancy here
i
}
// aggregate and wait for final result
val aggregated = Future.sequence(tasks)
val oneToNSum = Await.result(aggregated, 15.seconds).sum
「10個のスレッドで実行する」場合は、スレッドを使用します。 Scalaのアクターモデル。これは通常、Scalaは並行性に適している、hidesなど)あなたがそれらを表示しないように詳細。
アクターを使用するか、先物を使用して単純な計算を行うだけで、それらを50000個作成して実行できます。問題に直面するかもしれませんが、それらは異なる性質のものです。