학습
Scala 비동기 프로그래밍 기초 (Futures)
Scala 비동기 프로그래밍 기초 (Futures) — 중급
비동기 프로그래밍 기초 (Futures)
1. 도입 (왜 배워야 하는가)
비동기 프로그래밍은 현대 소프트웨어 개발에서 필수적인 기술로, 특히 웹 애플리케이션과 같은 I/O 중심의 서비스에서 매우 중요합니다. 비동기 프로그래밍을 사용하면, 서버가 여러 작업을 동시에 처리할 수 있어 사용자에게 더 빠르고 원활한 경험을 제공합니다. 만약 비동기 프로그래밍을 모른다면, 애플리케이션이 사용자 요청을 처리하는 동안 다른 작업이 차단되어 성능 저하를 초래할 수 있습니다. 예를 들어, 사용자가 웹페이지에서 버튼을 클릭했을 때, 서버가 응답을 기다리는 동안 화면이 멈춰버린다면 사용자는 불편을 느끼고 이탈할 수 있습니다.
2. 핵심 개념 설명
비동기 프로그래밍에서 가장 중요하게 다루는 개념은 "Future"입니다. Future는 비동기적으로 실행되는 작업의 결과를 나타내는 객체입니다. 이 객체는 작업이 완료되면 결과를 반환하거나 예외를 던질 수 있습니다.
비유
Future는 마치 친구에게 음식을 주문하고, 음식이 배달될 때까지 기다리지 않고 다른 일을 할 수 있는 상황과 비슷합니다. 음식을 주문하는 것은 비동기 작업이며, 주문의 결과(배달된 음식)는 Future로 표현될 수 있습니다.
관련 용어 정리
| 용어 | 설명 |
|---|---|
| Future | 비동기 작업의 결과를 나타내는 객체 |
| Promise | Future의 결과를 나중에 제공하기 위한 객체 |
| Await | Future의 결과가 준비될 때까지 기다림 |
3. 기본 코드 예제
아래는 Scala에서 Future를 사용하는 기본적인 예제입니다.
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
// 비동기 작업 정의
val futureResult: Future[Int] = Future {
// 2초 대기 후 10을 반환
Thread.sleep(2000)
10
}
// 결과를 출력
futureResult.foreach(result => println(s"결과는: $result"))
실행 결과
(2초 후) 결과는: 10
코드 한 줄씩 동작 설명
import scala.concurrent.Future: Future 클래스를 사용하기 위해 필요한 라이브러리를 가져옵니다.import scala.concurrent.ExecutionContext.Implicits.global: 비동기 작업을 실행할 스레드 풀을 설정합니다.val futureResult: Future[Int] = Future {...}: 비동기 작업을 정의하고, 결과를 Future 객체에 저장합니다.Thread.sleep(2000): 2초 동안 대기합니다. 이 부분은 비동기 작업의 예제입니다.futureResult.foreach(result => println(s"결과는: $result")): Future의 결과가 준비되면 결과를 콘솔에 출력합니다.- 문제: Future가 완료되기 전에 값을 가져오려 하므로 예외 발생 가능.
- 올바른 예:
- 문제: Blocking 호출을 사용하면 비동기의 장점을 잃게 됨.
- 올바른 예: Future의 결과를 비동기로 처리.
- Future는 비동기 작업의 결과를 나타내는 객체입니다.
- 비동기 프로그래밍은 애플리케이션의 응답성을 높이는 데 필수적입니다.
- 비동기 작업의 결과를 사용할 때는
foreach를 활용해야 합니다. - Blocking 호출은 피하고, 결과를 비동기로 처리하는 것이 좋습니다.
4. 실전 활용 예제
예제 1: 쇼핑몰에서 장바구니의 총 가격 계산
고객이 장바구니에 담은 상품의 총 가격을 비동기로 계산할 수 있습니다.
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
def calculateTotalPrice(cartItems: List[Double]): Future[Double] = Future {
// 장바구니의 총 가격 계산
cartItems.sum
}
val items = List(100.0, 200.0, 300.0)
calculateTotalPrice(items).foreach(total => println(s"장바구니 총 가격: $total"))
예제 2: 데이터베이스에서 사용자 정보 조회
데이터베이스에서 사용자 정보를 비동기로 조회하여 애플리케이션의 응답성을 높일 수 있습니다.
def fetchUserData(userId: String): Future[String] = Future {
// 데이터베이스에서 사용자 정보를 조회 (가정)
Thread.sleep(1000) // 조회 시간 시뮬레이션
s"User data for ID: $userId"
}
fetchUserData("12345").foreach(data => println(data))
5. 흔한 실수와 주의사항
1. Future의 결과를 직접 사용하려는 실수
// 잘못된 예
val result = futureResult.value.get
futureResult.foreach(result => println(s"결과는: $result"))
2. Blocking 호출 사용
// 잘못된 예
val blockingResult = Await.result(futureResult, 10.seconds)
6. 정리
다음에 학습하면 좋은 주제는 Promise, Akka Streams와 같은 더 복잡한 비동기 패턴입니다.