Actor e gestione strutturata dello stato
Utilizzi pattern in stile actor per serializzare l'accesso allo stato nel codice concorrente.
Actor e gestione strutturata dello stato è una lezione Kotlin Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Kotlin Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Kotlin Academy include 4 lezioni in totale.
Che cos'è un actor?
Un actor è una coroutine che possiede uno stato mutabile privato e comunica tramite un canale. Il codice esterno non accede mai direttamente allo stato, ma solo tramite messaggi.
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)
}
}
}Utilizzo dell'actor
Invii messaggi all'actor utilizzando send. L'actor li elabora uno alla volta, serializzando l'accesso allo stato.
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()
}L'actor sostituisce Mutex
Gli actor eliminano la necessità dei mutex rendendo sequenziale l'accesso allo stato per progettazione. Tutte le modifiche avvengono all'interno di una sola coroutine.
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()
}Protocollo dei messaggi tipizzato
Definisca il protocollo dei messaggi come una gerarchia di classi sealed per gestire in modo esaustivo l'espressione when dell'actor.
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 onlyMacchina a stati come actor
Gli actor sono macchine a stati naturali: le transizioni dello stato interno avvengono atomicamente in risposta ai messaggi.
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()
}Builder actor()
Il builder di coroutine actor { } crea un attore con una casella di posta basata su un canale. L'attore è una coroutine che elabora i messaggi provenienti da 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
}Arrestare un attore
Chiuda il canale di invio dell'attore con close(). Il ciclo for nell'attore termina, consentendo di eseguire le operazioni di pulizia prima che la coroutine finisca.
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)
}Attori con backpressure
Imposti la capacità del canale dell'attore per applicare la backpressure: i mittenti vengono sospesi quando la casella di posta è piena.
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()
}Prestazioni: attore vs Mutex
Gli attori serializzano l'accesso senza contesa sui lock e sono adatti a stati complessi con più tipi di messaggio. Mutex è più semplice per un singolo contatore condiviso, ma è meno componibile.
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 per il pattern richiesta-risposta
Per i pattern richiesta-risposta all'interno di un attore, includa un CompletableDeferred nel messaggio. L'attore lo completa; il mittente lo attende.
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])
}
}Alternativa moderna: StateFlow + coroutineScope
Il builder actor è sperimentale e potrebbe essere deprecato. L'alternativa moderna è una classe ViewModel o di servizio con un MutableStateFlow aggiornato da una singola coroutine.
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) }
}Verifica rapida
In che modo gli attori garantiscono un accesso sicuro allo stato condiviso concorrente?
Riepilogo
Gli attori incapsulano lo stato mutabile in una singola coroutine ed espongono le operazioni come messaggi di canale tipizzati. Serializzano naturalmente l'accesso, supportano le macchine a stati ed eliminano la contesa sui lock, al costo di un livello di indirezione dovuto al passaggio di messaggi.
Impara Kotlin con un tutor IA — gratis
Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.
- Corsi
- 51
- Lezioni
- 203
Domande Frequenti
La lezione «Actor e gestione strutturata dello stato» è gratuita?
Sì — il testo completo di «Actor e gestione strutturata dello stato» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Kotlin Academy, passa a CoddyKit PRO. Il corso Kotlin Academy include 4 lezioni in totale.
Cosa imparerò in «Actor e gestione strutturata dello stato»?
Utilizzi pattern in stile actor per serializzare l'accesso allo stato nel codice concorrente. Eserciti Kotlin Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Kotlin Academy?
Non è richiesta alcuna esperienza precedente. Kotlin Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.
Quanto tempo richiede la lezione «Actor e gestione strutturata dello stato»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Kotlin Academy?
Sì. Ogni lezione Kotlin Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Basi dei Channel: send, receive e close
- Tipi di Channel: Rendezvous, Buffered, Conflated, Unlimited
- Mutex e Semaphore per lo stato condiviso
- Actor e gestione strutturata dello stato