Futureを使ってみよう

## はじめに

Futureを使ってみました。この記事では、Futureをネストした場合と並べた場合で、どのような順序で処理が実行されるかを確認します。

## Futureをネストした場合

Futureをネストした場合のコードを紹介して、その実行結果を紹介します。

使用したコードは次のようなコードです。

```Main.scala
object Main extends App {
  import scala.concurrent.{ Future, Await }
  import scala.concurrent.ExecutionContext.Implicits.global
  import scala.concurrent.duration.Duration

  println("main: " + Thread.currentThread.getId)

  val f1 = Future {
    println("future1: " + Thread.currentThread.getId)
    println("tokyo")

    Future {
      println("future2: " + Thread.currentThread.getId)
      println("kyoto")
    }
  }

  Await.ready(f1, Duration.Inf)
}
```

Awaitで、future1が完了することを待ちます。次のような実行結果になりました。

```
[info] Running Main
main: 20
future1: 21
tokyo
future2: 22
kyoto
```

Futureで包んだ処理は上から順番に実行されるようです。よって、future1の後にfuture2が実行されるようです。

念のため、次のようなコードも確認してみます。future2の処理時間が長い場合、future1の後にfuture2が実行されるかどうかを確認してみます。

```Main.scala
object Main extends App {
  import scala.concurrent.{ Future, Await }
  import scala.concurrent.ExecutionContext.Implicits.global
  import scala.concurrent.duration.Duration

  println("main: " + Thread.currentThread.getId)

  val f1 = Future {
    println("future1: " + Thread.currentThread.getId)
    println("tokyo")

    Future {
      println("future2: " + Thread.currentThread.getId)
      Thread.sleep(1000)
      println("kyoto")
    }
  }

  Await.ready(f1, Duration.Inf)
}
```

次のような結果になりました。一応、future1の後にfuture2が実行されたようですが、future2の処理が完了する前に処理が中断されたようです。

```
[info] Running Main
main: 20
future1: 21
tokyo
future2: 22
```

よく考えてみれば当然なことかもしれませんが、忘れがちです。メインスレッド(スレッドID20)でスレッドID21の完了は待ちますが、スレッドID22の完了は待ちません。

## Futureを並べた場合

Futureを並べた場合のコードを紹介して、その実行結果を紹介します。

使用したコードは次のようなコードです。

```Main.scala
object Main extends App {
  import scala.concurrent.{ Future, Await }
  import scala.concurrent.ExecutionContext.Implicits.global
  import scala.concurrent.duration.Duration

  println("main: " + Thread.currentThread.getId)

  val f1 = Future {
    println("future1: " + Thread.currentThread.getId)
    println("tokyo")

  }
  val f2 = Future {
    println("future2: " + Thread.currentThread.getId)
    println("kyoto")
  }

  Await.ready(f2, Duration.Inf)
  Await.ready(f1, Duration.Inf)
}
```

Awaitで、future2が完了することを待ち、future1が完了することを待ちます。次のような実行結果になります。

```
[info] Running Main
main: 20
future1: 21
tokyo
future2: 21
kyoto
```

future1が完了した後にfuture2が完了したようです。この場合、処理完了の順番と待ちの順番とは関係がないようです。

また、ネストした場合ではfuture1のスレッドIDとfuture2のスレッドIDが違うスレッドIDでしたが、この場合は同じスレッドIDになったようです。

念のため、次のようなコードも確認してみます。future2の処理時間が長い場合、future2の後にfuture1が完了するかどうかを確認してみます。

```Main.scala
object Main extends App {
  import scala.concurrent.{ Future, Await }
  import scala.concurrent.ExecutionContext.Implicits.global
  import scala.concurrent.duration.Duration

  println("main: " + Thread.currentThread.getId)

  val f1 = Future {
    println("future1: " + Thread.currentThread.getId)
    println("tokyo")

  }
  val f2 = Future {
    println("future2: " + Thread.currentThread.getId)
    Thread.sleep(1000)
    println("kyoto")
  }

  Await.ready(f2, Duration.Inf)
  Await.ready(f1, Duration.Inf)
}
```

次のような実行結果になります。future1が完了した後にfuture2が完了したようです。この場合も、処理完了の順番と待ちの順番とは関係がないようです。

不思議なことに、future2の後にfuture1が実行されることがありました。処理開始の順番は決まっていないようです。

```
[info] Running Main
main: 20
future2: 22
future1: 21
tokyo
kyoto

[info] Running Main
main: 20
future1: 21
tokyo
future2: 21
kyoto

[info] Running Main
main: 21
future1: 22
tokyo
future2: 22
kyoto
```

## まとめ

Futureをネストした場合と並べた場合を紹介しました。

基本的に、上から順番に実行されたようです。しかし、Futureを並べた場合、そうならないこともありました。

非同期処理の難しさを実感できたと思います。

## 参考URL

- [Scalaの並列処理・非同期処理 - Qiita](http://qiita.com/yhidai/items/74aa49ce0811e6ea262d)
- [Future と Promise - Scala Documentation](http://docs.scala-lang.org/ja/overviews/core/futures.html)
- [Scala - Futureにハマる - Qiita](http://qiita.com/mtoyoshi/items/78912722f8ccc13d80f6)
- [非同期プログラミングの難しさとScalaのFuture - Togetterまとめ](http://togetter.com/li/801021)
- [Future.successful と Future.apply](https://gist.github.com/tototoshi/c4b1c73a0d3d498b11d9)
- [Scala ExecutionContextって何 / Futureはスレッド立ち上げじゃないよ](http://mashi.hatenablog.com/entry/2014/11/24/010417)
- [モナドの本当の力を引き出す・・・モナドによる同期/非同期プログラミングの抽象化](http://d.hatena.ne.jp/xuwei/20150329/1427599055)