ScalaのFutureについて
前回、理解の薄いimplicitについて学習しブログに書いたのだけど、今回は使ったことの無いScalaのFutureについて学習したので、メモがてらここに残しておく。
何故Futureをキチンと扱えるようになりたかったのかと言うと、先日参加した勉強会でFutureの話が結構出てたから。
www.slideshare.net
リクエストの多いWebアプリだと、基本Futureで非同期処理させるのが良いっぽい、という理解。
もちろんすべてを網羅しているわけではないし、基本的な事しか書いてないと思うので、そこはご愛嬌。
Version
試したScalaのVersionは、今日も2.11.4デス。
準備
必要なimportはこの二つ。
import scala.concurrent.Future import scala.concurrent.ExecutionContext.Implicits.global
FutureクラスはFutureを使うため(当たり前w)。
globalについてはこちらを参照させていただきました。とても分かりやすい!
基本
val future: Future[Unit] = Future { // 非同期処理 }
こんな感じで定義すると、Future内の処理が非同期で実行されます。
非同期化する処理
非同期処理化前の処理として、こんな処理を定義。
単純に、変数resultの値に1と20を加算しているだけ。
var result: Int = 0 result += 1 println(s"result = ${result}") result += 20 println(s"result = ${result}") // 実行結果 // result = 1 // result = 21
実行結果の確認
非同期処理を確かめる方法として、どっかで見た下記の様な末尾回帰関数を定義。
「Future.value」メソッドでOption型が返却され、処理が完了している場合Someが、完了していない場合はNoneが返却される。
Someの中身は、定義したFutureの戻り値が格納されており、この戻り値の型に併せて、ジェネリクスを定義する(ここでは[String] ← この認識であってるかちょっと不安)。
ちなみに、「@tailrec」は末尾再帰になっていない場合コンパイルエラーにしてくれるアノテーション。
import scala.annotation.tailrec @tailrec def checkComplete(future: Future[String]): Unit = { future.value match { case Some(s) => println(s) case _ => checkComplete(future) } }
非同期化
この加算する処理をそれぞれ非同期処理する為に、二つのFutureでくるむ(くるむって表現あってるのか?)。
ちなみに、「Thread.currentThread.getId」は、定義した箇所が処理された時のスレッドIDを取得出来る。
var result: Int = 0 println(s"[Main] Thread Id = ${Thread.currentThread.getId} / result = ${result}") val future01: Future[String] = Future { result += 1 s"[future01] Thread Id = ${Thread.currentThread.getId} / result = ${result}" } val future02: Future[String] = Future { result += 20 s"[future02] Thread Id = ${Thread.currentThread.getId} / result = ${result}" }
実行してみる。
checkComplete(future01) checkComplete(future02) // 実行結果 // [Main] Thread Id = 1 / result = 0 // Success([future01] Thread Id = 11 / result = 1) // Success([future02] Thread Id = 11 / result = 21)
ThreadのIDが一緒なのは、future01の処理結果が帰るのが早すぎるのかな...。
これだとよく分からないので、下記の様にfuture01の処理を意図的に3秒停止させてみる。
val future01: Future[String] = Future { Thread.sleep(3000) result += 1 s"[future01] Thread Id = ${Thread.currentThread.getId} / result = ${result}" } // 実行結果 // [Main] Thread Id = 1 / result = 0 // Success([future01] Thread Id = 11 / result = 21) // Success([future02] Thread Id = 13 / result = 20)
future01の処理が3秒間止まっている間に、future02の処理が先に実行されたので、結果は
- future02の返却値が20
- future01の返却値が21
となった。
そしてThreadのIDもfuture01が11、future02が13となっている。
あと、100件のFutureを処理するこんなのも作ってみた。
(1 to 100).map { index => Future { result += index s"Date ${new java.util.Date} - Thread id ${Thread.currentThread.getId} / index = ${index} / result = ${result}" } } foreach { future => checkComplete(future) } // 実行結果 // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 1 / result = 3) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 2 / result = 3) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 3 / result = 6) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 4 / result = 10) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 5 / result = 15) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 6 / result = 21) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 7 / result = 28) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 8 / result = 36) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 9 / result = 45) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 10 / result = 55) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 11 / result = 66) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 12 / result = 78) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 13 / result = 91) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 14 / result = 105) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 15 / result = 120) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 16 / result = 136) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 17 / result = 153) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 18 / result = 171) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 19 / result = 190) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 20 / result = 210) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 21 / result = 231) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 22 / result = 253) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 23 / result = 276) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 24 / result = 300) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 25 / result = 325) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 26 / result = 378) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 27 / result = 378) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 28 / result = 406) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 29 / result = 435) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 30 / result = 465) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 31 / result = 528) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 32 / result = 528) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 33 / result = 561) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 34 / result = 595) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 35 / result = 630) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 36 / result = 666) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 37 / result = 703) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 38 / result = 741) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 39 / result = 780) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 40 / result = 820) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 41 / result = 861) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 42 / result = 903) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 43 / result = 946) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 44 / result = 990) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 45 / result = 1035) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 46 / result = 1081) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 47 / result = 1128) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 48 / result = 1176) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 49 / result = 1225) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 50 / result = 1275) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 51 / result = 1326) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 52 / result = 1378) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 53 / result = 1431) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 54 / result = 1485) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 55 / result = 1540) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 56 / result = 1596) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 57 / result = 1653) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 58 / result = 1711) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 59 / result = 1770) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 60 / result = 1830) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 61 / result = 1891) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 62 / result = 1953) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 63 / result = 2016) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 64 / result = 2080) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 65 / result = 2145) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 66 / result = 2211) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 67 / result = 2278) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 68 / result = 2346) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 69 / result = 2415) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 70 / result = 2485) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 71 / result = 2556) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 72 / result = 2628) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 73 / result = 2701) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 74 / result = 2775) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 75 / result = 2850) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 76 / result = 2926) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 77 / result = 3003) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 78 / result = 3081) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 79 / result = 3160) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 80 / result = 3240) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 81 / result = 3321) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 82 / result = 3403) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 83 / result = 3486) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 84 / result = 3570) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 85 / result = 3655) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 86 / result = 3741) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 87 / result = 3828) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 88 / result = 3916) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 89 / result = 4005) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 90 / result = 4095) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 91 / result = 4186) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 92 / result = 4278) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 93 / result = 4371) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 94 / result = 4465) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 95 / result = 4560) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 96 / result = 4656) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 97 / result = 4753) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 98 / result = 4851) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 15 / index = 99 / result = 4950) // Success(Date Tue Mar 17 20:51:48 JST 2015 - Thread id 13 / index = 100 / result = 5050)
ちなみに、ThreadIDが2つなのは、僕のMacのCPUがIntel Core2 Duoだから(だと思っている)。
いっちゃんええCPUで試してみたいなーwww
さいごに
つっこみあったらおねがいします。