Skip to content

Scala の並列コレクションが直列でしか動かないと思ったら・・・

Scala の並列コレクションが直列でしか動かないと思ったら・・・ published on Scala の並列コレクションが直列でしか動かないと思ったら・・・ へのコメントはまだありません

追記

やっぱり、並列コレクションを使うのはやめて、Future 使って、Execution Context とかをちゃんと設定する方法にした。

が、一応、以下の内容はそのまま残しておく。

並列コレクションを使う動機

今、いろんな API からデータを取ってきて、それらを検索可能にするっていう(元々は自分用の)サービスをちょこちょこ作っている。(興味のある方は以下のリンクより使ってみて、是非フィードバックを下さいませ↓)

Track Down Anything on GitHub, Slack or Google Drive | Commet

いろんな API からデータを取ってくるので、直列で実行すると、どっか1箇所の API が不調だったりしてレスポンスが遅いと、それに引きずられてしまうので、並列化しようと思った。

コード

元々のコードは、大雑把にはこんな感じ。

SomeDatabase.findAllApiEndpointsToCall.foreach { apiCall =>
  apiCall.execute
}

これを並列化しようとして、以下のコードにした。

# par をつけた
SomeDatabase.findAllApiEndpointsToCall.par.foreach { apiCall =>
  apiCall.execute
}

ログをみると、

02:08:35.008 [ForkJoinPool-3-worker-5] INFO xxxxx

という感じで、別スレッドで動くようになったようだけど、スレッド名が常に同じ=1つのスレッドしか使われていないらしい。

以下のドキュメントを見ると、設定変更出来るらしいので、やってみた。

Parallel Collections – Configuring Parallel Collections – Scala Documentation

val apiCalls = SomeDatabase.findAllApiEndpointsToCall.par

# TaskSupport なるものを作成して、コレクションのプロパティにセット
val taskSupport = new ForkJoinTaskSupport(new scala.concurrent.forkjoin.ForkJoinPool(4)) # 4並列
apiCalls.tasksupport = taskSupport

apiCalls.foreach { apiCall =>
  apiCall.execute
}

これで、とりあえず並列で処理されるようになった。

これでいいのか?

メデタシメデタシ・・・じゃない気がする。並列処理をしたいところは、ここ以外にも沢山あるし、その度に tasksupport プロパティをセットするのはだるい。ExecutionContext みたいに、設定ファイルで簡単に設定できないものだろうか。

-D とかで設定できるらしい

parallel processing – Set the parallelism level for all collections in Scala 2.10? – Stack Overflow

↑のページによれば、システムプロパティを(-D とか setProperty とかで)セットすればその設定になるらしい。うまくいってるっぽい。

プロパティをいじるとかあまりやったことないんだけど、こんな感じ。

val props = System.getProperties()
props.setProperty("scala.concurrent.context.minThreads", "2")
props.setProperty("scala.concurrent.context.numThreads", "x1.5")
props.setProperty("scala.concurrent.context.maxThreads", "4")

パッケージオブジェクトをリフレクションでいじる

上の方法でうまく行かなかった人が、別の方法を編み出してた。

How do I set the default number of threads for Scala 2.10 parallel collections? – Stack Overflow

scala.collection.parallel.`package` の中身をリフレクションでいじるというもの。バージョンが変わった時に動かなくなる可能性もありそう。

まとめ

StackOverflow のどっかにも書いてあったけど、インターフェースとして使いづらいし、ドキュメントも1つのコレクションの設定を変更する方法しか書いてなくて困る。並列コレクションって、使ってる人があまりいないのだろうか。

 

 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です