[AD] Scalaアプリケーションの開発・保守は合同会社ミルクソフトにお任せください
この記事ではFuture
クラスを使って非同期処理をする方法を解説します。
事前準備をする
まずは以下のListBuffer
について考えてみます。
val buffer: ListBuffer[String] = ListBuffer()
このbuffer
に対して、処理の進捗状況を文字列で書き込んでいくプログラムを想定します。
ふたつのメソッドを用意して、それぞれ同時に実行して並行に処理してみましょう。
2つのメソッドを準備する
まずは1つ目のメソッド。
def process1(): Unit = buffer += "start first process" Thread.sleep(100) buffer += "finish first process"
開始時と終了時にそれぞれ文字列をbuffer
に対して挿入しています。
これはすこし時間がかかる処理であるのを模して、Thread.sleep
を挟んでいます。
そして2つ目のメソッド。
def process2(): Unit = buffer += "start second process" buffer += "finish second process"
こちらは即座に処理が終了するのを模して、開始直後に終了時の文字列をbuffer
に対して挿入します。
process1
もprocess2
も同期的に実行するメソッドです。
実行コンテキスト(ExecutionContext
)を準備する
Futureで非同期処理を行うには、実行コンテキスト(以下、ExecutionContext
)を具体的に用意する必要があります。
Scalaにおける実行コンテキストとは、特定の処理がどのように実行されるべきであるのかについてのきまりです。
ExecutionContext
は、その実行コンテキストについて、実際にどのように実行されるかを定めたクラスです。
Future
を使用して処理する際には、どのようなExecutionContext
にて実行するべきかを示してあげましょう。
ここでは、Scalaが標準で用意しているExecutionContext
を使用することにします。
Scalaのプログラムは、特に非同期処理をしていない限り、標準のExecutionContext
において実行されています。
標準のExecutionContext
では、JVMが使用できるプロセッサ数まで並行に処理することができます。
つまり、もともとの処理に加えて、プロセッサ数 - 1個の処理まで並行に処理することができるわけですね。
標準のExecutionContext
を使用するには、以下のようにします。
import scala.concurrent.ExecutionContext.Implicits.global
Future
に対してExecutionContext
を暗黙的に渡したい場合には、後者のようにします。
Future
の各メソッドは暗黙のパラメータとしてExecutionContext
をとります。
したがって後者のようにすると毎回ExecutionContext
を渡す手間が省けて、コードを簡略化することができます。
また、Future
を使用する都度明示的にExecutionContext
を渡したい場合には、前者のようにすればOKです。
import scala.concurrent.ExecutionContext.global
非同期処理を実行する
では実際に非同期処理を実行してみましょう。
先述のメソッド、process1
とprocess2
を同時に実行するとどうなるかを見てみましょう。
以下のようにメソッドをFuture( )
で囲むと、非同期処理として実行することができます。
val f1 = Future(process1()) val f2 = Future(process2())
process1
は非同期処理として即座に実行され、直後にprocess2
も実行されます。
したがって、実質的に同時に実行したことになります。
process1
を先に開始しましたが、process1
は時間がかかるため、process2
の方が先に終わると期待されます。
それでは、buffer
の中身を見てみましょう。
以下のようにするとf1
とf2
が完了した状態のbuffer
を返すことができます。
for { _ <- f1 _ <- f2 } yield buffer
buffer
の中身は以下のようになっています。
ListBuffer(start first process, start second process, finish second process, finish first process)
実際にprocess1
の開始、process2
の開始、process2
の完了、process1
の完了という順番になっていることがわかりますね。