Acteurs et gestion structurée de l’état
Utilisez des modèles de type acteur pour sérialiser l’accès à l’état dans du code concurrent.
Acteurs et gestion structurée de l’état est une leçon Kotlin Academy gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Kotlin Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Kotlin Academy comprend 4 leçons au total.
Qu’est-ce qu’un acteur ?
Un acteur est une coroutine qui possède un état mutable privé et communique via un canal. Le code externe n’accède jamais directement à cet état : il le fait uniquement par l’intermédiaire de messages.
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)
}
}
}Utiliser l’acteur
Envoyez des messages à l’acteur avec send. L’acteur les traite un par un, en sérialisant l’accès à l’état.
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’acteur remplace Mutex
Les acteurs éliminent le besoin de mutex en rendant l’accès à l’état séquentiel par conception. Toutes les modifications ont lieu dans une seule 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()
}Protocole de messages typé
Définissez votre protocole de messages sous la forme d’une hiérarchie de classes scellées afin de gérer tous les cas dans l’expression conditionnelle de l’acteur.
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 onlyMachine à états sous forme d’acteur
Les acteurs sont naturellement des machines à états : les transitions de l’état interne s’effectuent de manière atomique en réponse aux messages.
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()
}Générateur actor()
Le générateur de coroutines actor { } crée un acteur doté d'une boîte de réception de canal. L'acteur est une coroutine qui traite les messages provenant de 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
}Arrêter un acteur
Fermez le canal d'envoi de l'acteur avec close(). La boucle for de l'acteur se termine, ce qui permet d'effectuer le nettoyage avant la fin de la coroutine.
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)
}Acteurs avec rétropression
Définissez la capacité du canal de l'acteur pour appliquer une rétropression : les émetteurs sont suspendus lorsque la boîte de réception est pleine.
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()
}Performances : acteur ou Mutex
Les acteurs sérialisent l'accès sans contention sur les verrous et conviennent aux états complexes comportant plusieurs types de messages. Mutex est plus simple pour un compteur partagé unique, mais se combine moins bien.
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 pour les requêtes-réponses
Pour les modèles requête-réponse au sein d'un acteur, incluez un CompletableDeferred dans le message. L'acteur le termine et l'émetteur l'attend.
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])
}
}Alternative moderne : StateFlow + coroutineScope
Le générateur actor est expérimental et pourrait être déprécié. L'alternative moderne consiste à utiliser une classe ViewModel ou un service avec un MutableStateFlow mis à jour depuis une coroutine unique.
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) }
}Vérification rapide
Comment les acteurs garantissent-ils un accès sûr à l'état concurrent ?
Récapitulatif
Les acteurs encapsulent l'état mutable dans une coroutine unique et exposent les opérations sous forme de messages de canal typés. Ils sérialisent naturellement l'accès, prennent en charge les machines à états et éliminent la contention sur les verrous, au prix d'un niveau d'indirection lié au passage de messages.
Questions Fréquemment Posées
La leçon « Acteurs et gestion structurée de l’état » est-elle gratuite ?
Oui — le texte complet de « Acteurs et gestion structurée de l’état » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Kotlin Academy, passe à CoddyKit PRO. Le cours Kotlin Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Acteurs et gestion structurée de l’état » ?
Utilisez des modèles de type acteur pour sérialiser l’accès à l’état dans du code concurrent. Tu pratiques Kotlin Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer Kotlin Academy ?
Aucune expérience préalable n'est requise. Kotlin Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.
Combien de temps prend la leçon « Acteurs et gestion structurée de l’état » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon Kotlin Academy ?
Oui. Chaque leçon Kotlin Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Notions de base des canaux : send, receive et close
- Types de canaux : rendez-vous, avec tampon, fusionnés, illimités
- Mutex et Semaphore pour l’état partagé
- Acteurs et gestion structurée de l’état