Future

Ada·2023년 9월 6일

Akka

목록 보기
10/32

[ 퓨처란 무엇인가? ]

Future는 아직 계산되지 않은 값을 나타내며, 이 값은 언젠가 나중에 계산될 수 있다. 스칼라에서는 scala.concurrent.Future 패키지에 Future가 정의되어 있으며, 아카에서도 이를 사용한다.

퓨처는 다음과 같은 상황에서 유용하다.

  • 긴 실행 시간이 소요되는 작업을 수행할 때.

  • 네트워크 호출 또는 파일 읽기와 같은 느린 작업을 수행할 때.

  • 여러 작업을 병렬로 실행하고 그 결과를 기다려야 할 때.

[ 아카에서의 Future 사용 ]

아카에서는 주로 두 가지 방법으로 Future를 사용한다.

1. ask 패턴 :

액터에게 메시지를 보내고, 그 결과를 Future 로 받는다. 이를 위해서는 ask 메서드나 ? 연산자를 사용한다.

val future = ask(helloActor, SayHello("John"))
val future = helloActor ? SayHello("John")
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._

implicit val timeout: Timeout = Timeout(5.seconds)
val future = helloActor ? SayHello("John")



2. Pipe 패턴 :

이미 계산된 Future 값을 다른 액터에게 전달할 수 있다. pipeTo메서드를 사용하여 Future 의 결과를 액터에게 전달할 수 있다.

import akka.pattern.pipe

val futureResult: Future[String] = ...
futureResult pipeTo anotherActor





아래는 스칼라로 아카의 퓨처를 사용하는 예시 코드이다.

import akka.actor.{ Actor, ActorSystem, Props }
import akka.pattern.ask
import akka.util.Timeout
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global

// 액터 메시지 정의
case class SayHello(name: String)
case class HelloResponse(message: String)

// HelloActor 정의
class HelloActor extends Actor {
  def receive = {
    case SayHello(name: String) =>
      sender ! HelloResponse(s"Hello, $name!")
  }
}

object AskExample {
  def main(args: Array[String]): Unit = {
    // 액터 시스템 생성
    val system = ActorSystem("AskExampleSystem")

    // HelloActor의 인스턴스 생성
    val helloActor = system.actorOf(Props[HelloActor], "helloActor")

    // Timeout 정의 (액터에게 응답을 기다리는 시간)
    implicit val timeout: Timeout = Timeout(5.seconds)

    // ask 메서드를 사용하여 Future 얻기
    val future = helloActor ? SayHello("John")

    // Future 결과 처리
    future.map {
      case HelloResponse(message) => println(s"Received: $message")
      case _ => println("Something went wrong")
    }

    // 액터 시스템 종료 예시 (실제 애플리케이션에서는 적절한 시점에 종료해야 함)
    // system.terminate()
  }
}

메시지를 보내고자 하는 목적지에 해당하는 액터는 ask 메서드에 인수로 전달되며,
보내려는 메시지와 타임아웃 객체도 인수로 전달된다.

위의 예제에서 HelloActorSayHello 메시지를 받으면 HelloResponse 메시지를 sender 에게 다시 보낸다.

ask 메서드 (? 연산자 ) 를 사용하여 HelloActor 에게 SayHello 메시지를 보내고, 결과를 Future 로 받는다.

Future 의 결과는 map 함수를 사용하여 처리할 수 있다.

위의 예시에서는 결과가 HelloResponse 타입이면 그 내용을 출력하고, 그렇지 않으면 오류 메시지를 출력하고 있다.

[ Future 를 안전하게 사용하기 ]

Future가 성공하거나 실패할 때 수행할 동작을 지정할 수 있는 여러가지 방법이 있다.

onComplete

이 메서드는 Future 가 완성되었을 때 호출되는 콜백을 설정한다.

Success 또는 Failure 객체를 인자로 받아 처리한다.

import scala.concurrent.Future
import scala.util.{Success, Failure}
import scala.concurrent.ExecutionContext.Implicits.global

val future: Future[Int] = Future {
  42 // 대신 실제로 어떤 비동기 작업이 이루어질 수 있습니다.
}

future.onComplete {
  case Success(value) => println(s"Success! The answer is $value.")
  case Failure(e) => println(s"An error has occurred: ${e.getMessage}")
}

// result
성공적으로 완료됐다면: "Success! The answer is 42."
실패했다면: "An error has occurred: [에러 메시지]"

onSuccess & onFailure

onSuccess 는 Future 가 성공했을 때 실행되고, 성공한 값만 인자로 받는다.
onFailure 는 Future 가 실패했을 때 실행되고, 예외만을 인자로 받는다.

future.onSuccess {
  case value => println(s"Success! The answer is $value.")
}

future.onFailure {
  case e => println(s"An error has occurred: ${e.getMessage}")
}

// result
성공적으로 완료됐다면 (onSuccess): "Success! The answer is 42."
실패했다면 (onFailure): "An error has occurred: [에러 메시지]"

map & flatMap

map 과 flatMap 은 Future 의 결과에 함수를 적용한다.
이 함수들은 Future 가 성공적으로 완료되면 호출된다.

val futurePlusOne: Future[Int] = future.map { value =>
  value + 1
}

val futurePlusTwo: Future[Int] = future.flatMap { value =>
  Future.successful(value + 2)
}

// result
futurePlusOne의 값은 43
futurePlusTwo의 값은 44

recover & recoverWith

이 메서드들은 Future 가 실패했을 때 대체 값을 제공하거나, 대체 Future 를 제공한다.

val recovered: Future[Int] = future.recover {
  case e: Exception => -1
}

val recoveredWith: Future[Int] = future.recoverWith {
  case e: Exception => Future.successful(-1)
}

// result
원래 Future가 성공했다면, recovered와 recoveredWith는 원래 Future의 값,42를 가지게 됨.
원래 Future가 실패했다면, recovered와 recoveredWith는 -1 값을 가지게 됨.
profile
백엔드 프로그래머

0개의 댓글