0Pricing
Kotlin Academy · 강의

액터와 구조화된 상태 관리

동시 실행 코드에서 상태 접근을 직렬화하는 액터 스타일 패턴을 사용해 보세요.

액터와 구조화된 상태 관리은(는) CoddyKit의 무료 Kotlin Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Kotlin Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Kotlin Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

액터란 무엇입니까

액터는 비공개 변경 가능 상태를 소유하고 채널을 통해 통신하는 코루틴입니다. 외부 코드는 상태에 직접 접근하지 않고 메시지를 통해서만 접근합니다.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
sealed class CounterMsg
object Increment : CounterMsg()
class GetCount(val response: CompletableDeferred<Int>) : CounterMsg()
fun CoroutineScope.counterActor() = actor<CounterMsg> {
    var counter = 0
    for (msg in channel) {
        when (msg) {
            is Increment -> counter++
            is GetCount  -> msg.response.complete(counter)
        }
    }
}

액터 사용하기

send를 사용하여 액터에 메시지를 보내십시오. 액터는 메시지를 한 번에 하나씩 처리하여 상태 접근을 직렬화합니다.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
// (CounterMsg sealed class from previous scene)
fun main() = runBlocking {
    val counter = counterActor()
    repeat(100) { counter.send(Increment) }
    val response = CompletableDeferred<Int>()
    counter.send(GetCount(response))
    println("Count: ${response.await()}") // 100
    counter.close()
}

액터로 Mutex 대체하기

액터는 설계상 상태 접근을 순차적으로 만들어 뮤텍스가 필요하지 않게 합니다. 모든 변경은 하나의 코루틴 내부에서 발생합니다.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
sealed class Msg
object Inc : Msg()
data class Get(val d: CompletableDeferred<Int>) : Msg()
fun CoroutineScope.safeCounter() = actor<Msg> {
    var n = 0
    for (m in channel) when(m) {
        is Inc -> n++
        is Get -> m.d.complete(n)
    }
}
fun main() = runBlocking {
    val a = safeCounter()
    repeat(1000) { a.send(Inc) }
    val d = CompletableDeferred<Int>()
    a.send(Get(d))
    println(d.await()) // 1000
    a.close()
}

타입이 지정된 메시지 프로토콜

액터의 when 표현식에서 모든 경우를 빠짐없이 처리할 수 있도록 메시지 프로토콜을 봉인된 클래스 계층 구조로 정의하십시오.

sealed class BankMsg
data class Deposit(val amount: Double) : BankMsg()
data class Withdraw(val amount: Double, val result: CompletableDeferred<Boolean>) : BankMsg()
data class Balance(val result: CompletableDeferred<Double>) : BankMsg()
// Actor holds balance privately — outside code sends messages only

액터로 상태 머신 만들기

액터는 자연스러운 상태 머신입니다. 메시지에 응답하여 내부 상태 전환을 원자적으로 수행합니다.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
enum class TrafficState { RED, GREEN, YELLOW }
fun CoroutineScope.trafficLight() = actor<Unit> {
    var state = TrafficState.RED
    for (msg in channel) {
        state = when (state) {
            TrafficState.RED    -> TrafficState.GREEN
            TrafficState.GREEN  -> TrafficState.YELLOW
            TrafficState.YELLOW -> TrafficState.RED
        }
        println("State: $state")
    }
}
fun main() = runBlocking {
    val light = trafficLight()
    repeat(6) { light.send(Unit) }
    light.close()
}

actor() 빌더

actor { } 코루틴 빌더는 채널 수신함이 있는 액터를 생성합니다. 액터는 channel에서 메시지를 처리하는 코루틴입니다.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun CoroutineScope.logActor() = actor<String>(capacity = Channel.BUFFERED) {
    val log = mutableListOf<String>()
    for (msg in channel) {
        log.add(msg)
        println("[LOG] $msg")
    }
    println("Log entries: ${log.size}")
}
fun main() = runBlocking {
    val logger = logActor()
    repeat(5) { logger.send("Event $it") }
    logger.close()
    // actor finishes after close
}

액터 중지하기

close()로 액터의 send 채널을 닫습니다. 액터의 for 루프가 종료되므로 코루틴이 끝나기 전에 정리 작업을 수행할 수 있습니다.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun main() = runBlocking {
    val actor = actor<String> {
        for (msg in channel) println("Got: $msg")
        println("Actor done")
    }
    actor.send("hello")
    actor.send("world")
    actor.close()
    // Wait for actor to finish
    delay(50)
}

백프레셔를 사용하는 액터

액터의 채널 용량을 설정하여 백프레셔를 적용합니다. 수신함이 가득 차면 전송자가 일시 중단됩니다.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
fun CoroutineScope.slowProcessor() = actor<Int>(capacity = 2) {
    for (item in channel) {
        delay(100) // slow processing
        println("Processed: $item")
    }
}
fun main() = runBlocking {
    val proc = slowProcessor()
    repeat(5) { proc.send(it) } // sender suspends when capacity full
    proc.close()
}

액터와 Mutex 성능 비교

액터는 잠금 경합 없이 접근을 직렬화하므로 여러 메시지 유형을 사용하는 복잡한 상태에 적합합니다. Mutex는 하나의 공유 카운터에는 더 단순하지만 조합성이 떨어집니다.

import kotlinx.coroutines.*
import kotlinx.coroutines.sync.*
// For a simple counter: Mutex is fine
val mutex = Mutex()
var simpleCounter = 0
// For complex state + multiple operations: Actor is cleaner
// Actor: messages describe intent; state changes are encapsulated
fun main() = runBlocking { println("Choose based on state complexity") }

요청-응답에 CompletableDeferred 사용하기

액터 내부에서 요청-응답 패턴을 사용하려면 메시지에 CompletableDeferred를 포함합니다. 액터가 이를 완료하고 전송자가 await합니다.

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
data class Query(val key: String, val reply: CompletableDeferred<String?>)
fun CoroutineScope.cacheActor() = actor<Any> {
    val cache = mutableMapOf<String, String>()
    for (msg in channel) when (msg) {
        is Pair<*, *> -> cache[msg.first as String] = msg.second as String
        is Query -> msg.reply.complete(cache[msg.key])
    }
}

현대적인 대안: StateFlow + coroutineScope

actor 빌더는 실험적이며 더 이상 사용되지 않을 수 있습니다. 현대적인 대안은 ViewModel 또는 서비스 클래스에서 MutableStateFlow를 하나의 코루틴에서 업데이트하는 방식입니다.

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
class CounterService(scope: CoroutineScope) {
    private val _count = MutableStateFlow(0)
    val count = _count.asStateFlow()
    private val events = kotlinx.coroutines.channels.Channel<Unit>()
    init {
        scope.launch {
            for (e in events) _count.value++
        }
    }
    fun increment() { events.trySend(Unit) }
}

빠른 확인

액터는 동시 상태 접근을 어떻게 안전하게 보장합니까?

정리

액터는 변경 가능한 상태를 하나의 코루틴에 캡슐화하고, 작업을 타입이 지정된 채널 메시지로 노출합니다. 액세스를 자연스럽게 직렬화하고 상태 머신을 지원하며 잠금 경합을 제거하지만, 메시지 전달에 따른 간접성 비용이 발생합니다.

자주 묻는 질문

“액터와 구조화된 상태 관리” 강의는 무료인가요?

네 — “액터와 구조화된 상태 관리” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Kotlin Academy 강의 전체를 잠금 해제할 수 있습니다. Kotlin Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“액터와 구조화된 상태 관리”에서 뭘 배우나요?

동시 실행 코드에서 상태 접근을 직렬화하는 액터 스타일 패턴을 사용해 보세요. 브라우저에서 직접 실행하는 실습 코드로 Kotlin Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Kotlin Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Kotlin Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“액터와 구조화된 상태 관리” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Kotlin Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Kotlin Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 채널 기초: send, receive 및 close
  2. 채널 타입: 랑데부, 버퍼링, 융합, 무제한
  3. 공유 상태를 위한 Mutex와 Semaphore
  4. 액터와 구조화된 상태 관리
← Kotlin Academy(으)로 돌아가기