まめぞうの技術メモ

IT関連で勉強したことをメモします

ScalaのFutureの使い方【並行処理】

今回は、Javaの発展形のScala言語で並行処理をする方法を書きます。

少し前まではJavaの並行処理、マルチスレッドを調べていたんですが、最近の潮流はJavaよりもScalaだろうということで、Scalaについても調べてみるとします。

並行処理では処理結果を待つのを忘れずに

並行処理をする時に気をつけないといけないのは、並行処理の結果が返ってくるのを待ってから、メイン側の次の処理に移ることです。

並行処理やマルチスレッドプログラミングの初心者がよくここを間違えて、

並行処理の結果を受け取らずにメインの処理を進めるプログラムを書いてしまい、返ってくる変数の中身が空のまま次の処理に進んでエラーになる、

なんてことが起こりがちです。

例えばキャッチボールでいうと、相手からボールが返ってくるまえに、ボールを投げようとしても、ボールがないので投げられませんよね。そんなイメージです。

ボールが返って来てから、次のプレーに進む
ボールが返って来てから、次のプレーに進む

 並行処理の結果を待つには、Future を使います。

## Futureの使い方 それでは、並行処理結果を待つためのFutureの使い方です。

Futureは変数の型です。

変数宣言をするときに、Future[返ってくる変数の型] と書けば定義できます。

また、Futureを宣言したときは、右辺に Future{ 並行処理の内容 } として、処理の内容を書きます。

具体例はこんな感じです。

    val hello : Future[String] = Future{
      Thread.sleep(1000)
      "Hello"
    }

次に、実際に処理を待つAwaitの説明です。

Awaitの使い方

処理の結果を待つには、「Await.ready」を使います。

左辺に結果を待つ Future変数、右辺に最大の待ち時間を書きます。

Await.ready(hello, 5 seconds)

結果はforeachなどで取り出そう

最後に、結果を取り出すときに、そのままprintしてしまうと、余計なゴミが入ってしまいます。下のサンプルのように、foreach等で中の要素を取り出すようにしましょう。

    println("--- ただのprintlnでは、「Future(Success(Hello))」になってしまう ---")
    println(hello)


    //値の出力方法
    println("--- foreeeachで中の要素を取り出そう ---")
    hello.foreach { s: String => println(s)}

実行結果はこんな感じです。

実行結果

サンプルプログラム

それでは、サンプルプログラムです。

1秒後に「Hello」って返してくれるだけの関数を呼んで、Future型に格納するよう準備し、結果を待って、要素を取り出して出力するプログラムです。

import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._

object FutureTest {

  /**
    * メインメソッド
    * @param args
    */
  def main(args: Array[String]): Unit = {
    val testHello : Future[String] = Future{
      // 1秒後に Hello を返すreturnHelloメソッドを実行
      returnHello()
    }

    // testHelloに値が入るのを、最大5秒待つ
    Await.ready(testHello, 5 seconds)

    println("--- ただのprintlnでは、「Future(Success(Hello))」になってしまう ---")
    println(testHello)


    //値の出力方法
    println("--- foreeeachで中の要素を取り出そう ---")
    testHello.foreach { s: String => println(s)}
  }

  /**
    * 1秒後にHelloと返すだけのメソッド
    */
  def returnHello(): String ={
    Thread.sleep(1000)
    return "Hello"
  }
}

動いたでしょうか? 気になったら試してみてください。