[Scala] Await.result에서 Future로 환승

8037 단어 Scala

환승한 경위와 설명



우선 DB로부터 데이터 가져오는 처리를 전부 Await.result로 해 왔습니다만, 여러가지 이유로 Future로 환승하기로 했습니다.
Await.result가 안 좋은 이유로는 이쪽의 기사가 참고가 됩니다.

참고) Await.result는 피합시다.

자꾸 설명하면
  • Await.result : 계속 처리를 기다리고 계속해 thread가 해방되지 않는다
  • Future : 처리가 끝나면 처리를 재개한다. 그때까지 스레드는 해제됩니다

  • 스크립트의 실행이 끝날 때까지 계속 PC 앞에서 기다리고 있는 상태라고 생각하면 이미지하기 쉬울까라고.

    Await.result의 이미지

    스크립트가 끝날 때까지 계속 화면 보고 기다리고 있다.
    다른 작업을 할 수 없다

    사용 스레드 수는 2
  • 스크립트 실행 프로세스
  • 스크립트 돌아올 때까지 계속 화면 보고 있는 인물



  • Future 이미지

    스크립트 실행이 끝나고 나서 처리를 하면 된다고 알고 있다.
    다른 것이 가능하다. 라면도 먹을 수 있다

    사용 스레드 수는 1
  • 스크립트 실행 프로세스 전용



  • 그렇다면 라면을 먹을 수있는 Future로 갈아갑시다.

    DB 취득 처리를 Await.result에서 Future로 변경



    지금의 코드가 이런 느낌입니다.
    def findUser(userId: Int): Try[Option[User]] = {
        val sql =
          sql"""
                SELECT id, name
                FROM   user
                WHERE  user_id = "#${userId}"
          """.as[User]
    
        Try(Await.result(db.run(sql), Duration.Inf))
      }
    

    이것을 Future에 이런 느낌으로 바꾸어 보겠습니다. db.run 로 바꾼 것 뿐이네요.
      def findUser(userId:Int): Future[Option[User]] = {
        db.run(
          sql"""
                SELECT id, name
                FROM   user
                WHERE  user_id = "#${userId}"
          """.as[User]
        )
      }
    

    이제 Future형으로 돌아오게 됩니다. 다른 방법도 있을까 생각하기 때문에 일례 정도에.

    코드 사용 측을 Future로 변경



    여담입니다만, Await.result 그렇다면 처리가 종료하고 나서 돌아오기 때문에 get 해도 OK입니다.
    반대로 Future는 처리가 끝나지 않은 상태의 것이 반환되기 때문에 직접 getNone.get 입니다. (이것으로 1회 실장해 했다)

    지금의 코드가 이런 느낌입니다.
  • Try의 내용을 match로 취득하고, Option의 내용을 get로 취득
  •   // 返り値 : Try[Option[User]]
      hogeRepository.findUser match {
        case Success(OptionUser) =>
          OptionUser.get
        case Failure(e) => // エラー処理
      }
    

    이런 식으로 다시 작성했습니다.
  • 맵에서 Future가 반환 된 후 이후의 처리를 실행합니다
  • Option의 내용을 get로 취득
  •   // 返り値 : Future[Option[User]]
      hogeRepository.findUser.map { maybeUser =>
        maybeUser.get
      }
    

    Future의 에러 처리는 recover 로 쓸 수 있는 것 같기 때문에, 최종적으로는 이런 느낌입니다.
      // 返り値 : Future[Option[User]]
      val futureUser = hogeRepository.findUser.map { maybeUser =>
        maybeUser.get
      }.recover {
        // エラー処理
        case e => {
          println(e)
          System.exit(1)
        }
      }
    

    호출측도 바꾸지 않으면 안 되기 때문에 도중부터 이행을 생각하고 있는 사람은 조금 뼈가 부러질지도 모르겠네요.

    이것으로 대량의 액세스에도 견딜 수 있을 것 같은 Future의 혜택을 받을 수 있는 코드로 재기록할 수 있었습니다!

    여담



    처리의 흐름 속에서, Seq[Future[String]] 같게 되어 Future[Seq[String]] 하고 싶다! 따위 때는 sequence 를 사용하면 좋은 느낌으로 처리할 수 있습니다.
        val seqFutureStrings :Seq[Future[String]] = hogeRepository.findStrings
        // Futureの入れ子の順番を逆にする
        val futureSeqStrings :Future[Seq[String]] = Future.sequence(futureNames)
    
        futureSeqStrings.map { Strings =>
          Strings.mkString(",")
        }
    

    좋은 웹페이지 즐겨찾기