📘
【Scala】Future.sequenceで実行した場合に元のSeqの順序が保持されるのを確認してみる
概要
Scalaで非同期処理を実装した場合Future
を使用されると思います。Futureの機能として、複数のFutureを並列に実行するものがありまして、Futureをマスターする -コンパニオンオブジェクト操作-で紹介されているFuture.sequence
が挙げられます。
このFuture.sequence
ですが、実行された結果は元のSeqが保持される仕様となっています。Asynchronous programming with Scala Futuresの記事で、紹介されている内容になります。ということで、この順序が保持されるのを実際に実装して確認してみたので、メモ書きとして残しておきます。
確認方法
同エンドポイントのAPIにリクエストのソート順(Seqで持つ)だけ変えて、Future.sequence
でリクエストを投げます。結果のSeqから、リクエストのソート順のSeqと同じ順序になっているか確認していきます。
なお、 確認用のAPIに今回はgBizINFOを使用しました。
実装サンプル
以下のソースで結果も順序が保持されることを確認しました。全ソースコードはこちらにアップしています。
なお、フレームワークにはAkkaHttp、JSONのパースにはcirceを使用しています。
CompanySearchUseCase.scala
import akka.actor.ActorSystem
import companyInfo.model.api.InitialResponse
import companyInfo.model.rest.GbizResponse
import companyInfo.rest.CompanyRestClient
import companyInfo.rest.query.CompanyQueryBuilder
import io.circe.generic.auto._
import io.circe.parser._
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, Future}
import scala.util.{Failure, Success}
object CompanySearchUseCase {
implicit val system = ActorSystem()
implicit val executionContext = system.dispatcher
def getInitialDisplayCompanyInfo(): Either[Throwable, InitialResponse] = {
// このソートキーでリクエストを投げる
val sortKeys = Seq[String]("npmr", "roa", "roe", "equityRatio")
val futureSeq = Future.sequence(sortKeys.map(k =>
// APIリクエストを投げる処理(内容は記載を割愛)
CompanyRestClient.sendRequestToGbiz(
CompanyQueryBuilder.getQuery(sort = k)
)))
// 結果確認用のclass
val initialRes = InitialResponse()
var exceptionSeq = Seq.empty[Throwable]
val result = Await.ready(futureSeq, Duration.Inf).value.get
// sortKeysのSeqの順序になってるか確認する
result.foreach(seq => seq.zipWithIndex.foreach(res => {
res._1 match {
case Success(r) => {
decode[GbizResponse](r) match {
case Right(bizRes) => {
val companyResponses = bizRes.results.bindings.map(_.convertCompanyResponse())
// sortKeysの最初はnpmr
if (res._2 == 0) {
initialRes.byNpmrSortCompanies = companyResponses
// sortKeysの2番目はroa
} else if (res._2 == 1) {
initialRes.byRoaCompanies = companyResponses
// sortKeysの3番目はroe
} else if (res._2 == 2) {
initialRes.byRoeCompanies = companyResponses
// sortKeysの最後はequityRatio
} else {
initialRes.byEquityRatioCompanies = companyResponses
}
}
case Left(ex) => exceptionSeq :+= ex
}
}
case Failure(ex) => exceptionSeq :+= ex
}
}))
if (exceptionSeq.isEmpty) {
Right(initialRes)
} else {
Left(exceptionSeq.head)
}
}
}
Discussion