読者です 読者をやめる 読者になる 読者になる

ましめも

技術系メモ

Scala の Future ってどうやって使うの?Promiseって何?

"Scala Future" で検索して出てくるFutureの解説は、Scala公式サイトのドキュメントを除いて大体こんな感じで紹介されてることが多い。

import scala.concurrent._
import ExecutionContext.Implicits.global
Future {
  Thread.sleep(1000)
  println("hoge")
}
println("fuga")
//->
// fuga
// hoge

こういうFuture.applyにThread.sleepやIOのblockingをする例って非常に悪いと思っている。まるで、Futureでsleepするのが普通のコードっぽく見えるじゃん。違うの、単に説明の時に楽だからsleepしてるだけなの。説明コードが短くてすむの。ちょっと使ってるだけ。プロダクトコードでsleepするのやめろ。うわあ!!Future内でブロッキングやめろ!!そこみんなのトイレだから!無駄に占有しないで!

かといって、公式ドキュメント読めっていってもあのドキュメント長いし退屈。詳細に書いてあるのはわかるんだけど、初学者がちょっとFuture使ってみたいわ〜ってときに「ん?長いな別のサイト見るか」ってなってもしょうがない。

じゃあお前がかけよって言われるわけだが、なんか上手に書けない。前々から書こう書こうと思ってるんだけど。。箇条書きレベルでメモを残すので誰か日本語にしてください。

Scala の Future と Promise って何?

Promise なんて興味ない?いや、Futureの本体はPromiseといっても過言じゃないですよ。

Future[A]... いつか型Aの値が与えられる
Promise[A]... いつか型Aの値を与える

Future[A] いつか型Aの値が与えられる

Future にはいつか値が与えられる。値が与えられたときどういう動作をしてほしいのかは、foreach(等)で定義できる。

import scala.concurrent._
import ExecutionContext.Implicits.global
val a: Future[String] = getFuture()
// a にはいつかStringの値が与えられる。
// a に値が与えられたら、printlnは実行される。
a.foreach(e => println("値やっときたわ: " + e))
println("piyopiyo")

// ->
//   piyopiyo
//   値やっときたわ: ???

Promise[A] いつか型Aの値を与える

import scala.concurrent._
val b: Promise[String] = Promise[String]
// b にはいつかStringの値を与える

b.success("値あげるよ〜")
b.success("2回目実行するよ〜") // -> java.lang.IllegalStateException: Promise already completed.

これ何の役にたつの?

Promise[A] から Future[A] を作ることができる

Promise#futureを呼ぶと、Futureを作ることができる。
Promiseのsuccessを呼ぶと、その瞬間にFutureのforeach(等)が呼び出される。

import scala.concurrent._
import ExecutionContext.Implicits.global
val promise: Promise[String] = Promise[String]
val future: Future[String] = promise.future
future.foreach(e => println("値やっときたわ: " + e))
println("piyopiyo")
promise.success("こんにちは")
// ->
//  piyopiyo
//  値やっときたわ: こんにちは

じゃあ Future.apply って何

Futureの作り方ってFuture.applyじゃないんですか?!そう聞きました!こういう例で習いました!

val future: Future[A] = Future {
  Thread.sleep(1000)
  function1("fugahoge")
}

それでも作れるけど内部で同じように Promise 使ってます。ただの便利関数です。

まとめ

  • Future[A]... いつか型Aの値が与えられる
  • Promise[A]... いつか型Aの値を与える
  • Promise と Future で イベントハンドリング が楽に書ける
  • FutureでThread.sleepやめろ!(Thread.sleepやブロッキングすると当然暇なスレッドができます。それを意識してやってるなら別にいいです)

というのがわかる5分で読める解説ページができるといいな〜