だいたいよくわからないブログスマートフォン用の表示で見るだいたいよくわからないブログ2017-06-11TwitterのFutureについてのざっくりまとめ基本的に以下からそのまま取ってきています。GitHub説明用のざっくりポインタとしてまとめる予定だったのに、あれもこれもと欲張ってしまった代物。(その割に全部あるわけではない。playからfinagleに移行してきたりするとメソッド名が細かく違ったりするのに最初は戸惑いますが、Scala標準Futureとakkaのschedulerを使ったことがあれば、すぐ慣れつつ便利さを感じられると思います。例ではThread.sleepを呼びまくっていますが、そのへんの事情はScala標準のFutureと同じなのでちゃんとやるときはFuture.sleepやtimer.doLaterなどを使ったほうが良いです。基本的な作り方について。この作り方だとapplyも含めて全部同期実行になる点に注意。RuntimeException)apply/constScala標準Futureではapplyは非同期に実行されるが、TwitterFutureでのapplyは同期実行という違いに注意。RuntimeException))FutureをまとめるScala標準のFutureと同じくfor式を使うだけだと並行実行されないことがあるので注意。失敗した例外をSuccessにできる。caseはPartialFunctionなのでcaseにマッチしない例外はそのまま例外として扱われる。失敗した例外をSuccessにしたり別の例外に変換できる。caseはPartialFunctionなのでcaseにマッチしない例外はそのまま例外として扱われる。transformedByというメソッドもあるが、こちらはFutureTransformerを受け取る。FutureTransformerはJavaFriendlyと書いてあるので基本的にはtransformを使えば良い。FuturePool非同期実行したい場合はFuturePoolの力が必要。unboundedなので際限なく拡張される。非同期実行されるプールを自分で作る。interruptibleUnboundedPoolというキャンセルに対応したPoolもある。Timer系列Timerの種類を例ごとに変えてあるが使い方はどれも同じ。Timerの種類については後述。Future.sleep(3.seconds)Await.result(f)delayed完了が遅れるだけで計算自体はすぐ行われる点に注意。println("done"))Await.result(f)Timer#scheduleFutureのメソッドではないがついでなので紹介。1秒ごとに何度も実行する。キャンセル可能なTimerTaskを返す。2秒後に1回実行する。具体的な時刻を指定する。println("3sec!")}Await.result(f2)timerの話tl;dr;finagleを使っているならcom.twitter.finagle.util.DefaultTimerを使えばOKだが、blockingな重い処理をするなら自前で定義したほうがよいかも。finagle-netty4が依存パスにあればNetty4HashedWheelTimerが使われる。無くてもJavaTimer(isDaemon=true)が使われるので安心。するとユーザースレッドとして起動するため、明示的にcancelを呼ばないとtimerがGCされるまでプロセスが終了しなくなることがあるのでisDaemon=trueを指定するとよい。細かい話twitter/utilのこの手のメソッドはcom.twitter.util.Timerを要求してくる。finagleを使っていない場合、基本的にはJavaTimer(isDaemon=true)を、ある程度の性能が欲しい場合はScheduledThreadPoolTimerを使えば良さそう。finagleを使っている場合は、もう少し性能が出るタイマーがDefaultTimerとしてfinagle自体に用意されているのでそちらを使う方が良さそう。DefaultTimerのインスタンスは共通なのでblockingな処理を行う際は、そのスレッドがブロックされる可能性があるので分けたほうが良いかもしれない。(未検証)com.twitter.finagle.util.DefaultTimerの実装はServiceLoaderで一番最初に見つかったクラスを使う。ServiceLoaderで見つからなかった場合はwarningログが出つつcom.twitter.util.JavaTimerをdaemonThreadをONにした上で使うようになっている。http}の依存にある)がNetty4HashedWheelTimerを指定しているので大抵の場合はこれが読み込まれる気がする。https://github.com/twitter/finagle/blob/finagle-6.45.0/finagle-netty4/src/main/resources/META-INF/services/com.twitter.finagle.util.DefaultTimerもう一つcom.twitter.finagle.util.HashedWheelTimer.Defaultというややこしいものが存在するが、こちらはNetty3ベースのHashedWheelTimerを使っている。Netty3,4間のHashedWheelTimerの差はよくわかっていないが新しい方が良さそうなので基本的にはcom.twitter.finagle.util.DefaultTimerを使うのが良いだろう。Timerのロードにサービスローダーを使うようになったのはfinagle6.45から。コミットに書いてある通り、finagle-coreからnetty3依存を剥がすためにそうなっているらしい。selectは一番最初に終わったFutureの値と残りのFutureを返す。orはselectの2つ版。selectと異なり、先に終わった値が含まれるFutureのみを返す。selectIndexという一番最初に終わったSeq[Future[A]]のindexを返すメソッドもあるが割愛。traverseSequentially/collect/collectToTrytraverseSequentiallyは前のFutureが終了してから次を実行し、collectは同時に実行する。実装を見るとcollectでも結果に含まれる要素の順番は引数と同じになるっぽい。順序についてはドキュメントやコメントにはのってない気がする。collectToTryはcollectと異なり一部が失敗したときも成功し、一連の結果がTryで取得できる。