Concurrence et multithreading en Kotlin : niveau avancé

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Concurrence et multithreading en Kotlin : niveau avancé



Dans le développement moderne, une gestion efficace de la concurrence est la clé pour créer des applications rapides et réactives. Kotlin, grâce à son support intégré des coroutines, offre une boîte à outils puissante et flexible qui va bien au-delà des threads Java standard. Dans cet article, nous explorerons les concepts avancés de concurrence et de multithreading en Kotlin, y compris le travail avec Channel, Flow, Mutex et les subtilités des planificateurs.



1. Coroutines : plus en profondeur que les bases



Les coroutines sont des threads légers qui permettent d'écrire du code asynchrone dans un style impératif. Cependant, au niveau avancé, il est important de comprendre comment fonctionnent les dispatchers et les contextes de coroutines.



Planificateurs (Dispatchers)

Le choix du bon dispatcher est crucial pour les performances :

  • Dispatchers.Default — pour les tâches intensives en CPU (utilise par défaut un pool de threads égal au nombre de cœurs du processeur).
  • Dispatchers.IO — pour les opérations d'entrée/sortie (réseau, fichiers). Le pool de threads peut s'étendre jusqu'à 64 threads (ou plus, selon la configuration).
  • Dispatchers.Main — pour le thread UI (Android, JavaFX).
  • newSingleThreadContext et newFixedThreadPoolContext — pour créer vos propres pools.


import kotlinx.coroutines.*

fun main() = runBlocking { launch(Dispatchers.Default) { println("Tâche CPU sur ${Thread.currentThread().name}") } launch(Dispatchers.IO) { println("Tâche E/S sur ${Thread.currentThread().name}") }}


Concurrence structurée

L'une des principales fonctionnalités de Kotlin est la concurrence structurée. Elle garantit que les coroutines enfants se terminent avant la fin de la coroutine parente. Cela évite les fuites mémoire et simplifie la gestion du cycle de vie.



fun main() = runBlocking {    coroutineScope {        launch {            delay(1000)            println("Tâche 1 terminée")        }        launch {            delay(500)            println("Tâche 2 terminée")        }    }    println("Toutes les tâches terminées")}


2. Canaux (Channel) pour le transfert de données entre coroutines



Channel est l'équivalent d'une file d'attente bloquante (BlockingQueue), mais pour les coroutines. Il permet de transférer des données en toute sécurité entre coroutines, en suspendant l'expéditeur si le canal est plein, ou le récepteur si le canal est vide.



Types de canaux

  • RendezvousChannel (par défaut) — n'a pas de tampon. L'envoi est bloqué jusqu'à la réception.
  • BufferedChannel — possède un tampon de taille définie.
  • ConflatedChannel — ne stocke que la dernière valeur envoyée, en écrasant les précédentes.
  • UnlimitedChannel — tampon illimité (attention : peut provoquer un OOM).


import kotlinx.coroutines.*import kotlinx.coroutines.channels.*

fun main() = runBlocking { val channel = Channel<Int>(capacity = 5) // Canal tamponné

launch { for (i in 1..10) { channel.send(i) println("Envoyé : $i") } channel.close() }

launch { for (value in channel) { println("Reçu : $value") delay(100) } }}


Fan-out et Fan-in

Les canaux sont parfaits pour les modèles "fan-out" (un producteur, plusieurs consommateurs) et "fan-in" (plusieurs producteurs, un consommateur).



3. Flow : flux de données réactifs



Contrairement à Channel, qui est "chaud" (les données sont envoyées indépendamment de la présence d'un abonné), Flow est un flux "froid" qui

Blogs

Book Recommendations