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 메서드에 인수로 전달되며,
보내려는 메시지와 타임아웃 객체도 인수로 전달된다.

위의 예제에서 HelloActor 는 SayHello 메시지를 받으면 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개의 댓글