Le problème des courses de données
Comprenez pourquoi les modifications concurrentes sont dangereuses.
Le problème des courses de données est une leçon Swift Academy gratuite sur CoddyKit. Ceci est la leçon 1 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 Swift Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Swift Academy comprend 4 leçons au total.
Qu'est-ce qu'une course aux données ?
Une course aux données se produit lorsque deux fils d'exécution ou plus accèdent simultanément au même emplacement mémoire, qu'au moins un de ces accès est une écriture et qu'aucune synchronisation n'existe entre eux.
Le résultat est un comportement indéfini : valeurs corrompues, plantages ou erreurs qui n'apparaissent que sous forte charge.
État mutable partagé
La cause fondamentale des courses aux données est l'état mutable partagé. Si plusieurs tâches peuvent lire et écrire la même variable, l'ordre des opérations devient imprévisible.
Le compteur ci-dessous peut perdre des incréments, car count += 1 est une opération de lecture-modification-écriture et non une opération atomique.
final class Counter {
var count = 0
func increment() {
count += 1 // read, add, write: not atomic
}
}Pourquoi des incréments sont perdus
L'instruction count += 1 est compilée en trois étapes : charger la valeur, lui ajouter un, puis la stocker à nouveau.
Si deux fils d'exécution chargent 5 en même temps, ils stockent tous deux 6 et l'un des incréments disparaît.
// Thread A loads 5
// Thread B loads 5
// Thread A stores 6
// Thread B stores 6 <-- lost updateDéchirement des valeurs volumineuses
Au-delà des mises à jour perdues, des écritures simultanées dans des valeurs composées de plusieurs mots, comme une structure ou une valeur de 64 bits sur certaines plateformes, peuvent se déchirer : le lecteur voit la moitié d'une écriture et la moitié d'une autre.
struct Point { var x: Double; var y: Double }
var p = Point(x: 0, y: 0)
// Concurrent writes may leave x from one write and y from anotherL'ancienne solution : lock
Avant la concurrence de Swift, le remède classique était un lock (verrou d'exclusion mutuelle). Un seul fil d'exécution détient le lock à la fois, ce qui sérialise les accès.
Les lock fonctionnent, mais sont faciles à mal utiliser : déverrouillages oubliés, interblocages et inversion de priorité.
import Foundation
final class SafeCounter {
private let lock = NSLock()
private var count = 0
func increment() {
lock.lock()
defer { lock.unlock() }
count += 1
}
}Files DispatchQueue séquentielles
Une autre approche classique consiste à utiliser une file DispatchQueue séquentielle. Toutes les modifications sont dirigées vers une seule file et ne se chevauchent donc jamais.
import Foundation
final class QueueCounter {
private let queue = DispatchQueue(label: "counter")
private var count = 0
func increment() {
queue.async { self.count += 1 }
}
}Pourquoi la synchronisation manuelle est fragile
Les lock et les files reposent sur la discipline. Le compilateur ne vérifie pas que chaque accès est protégé.
Il suffit qu'une lecture non protégée se glisse quelque part pour que la course réapparaisse. Il n'existe aucune garantie à la compilation.
// Nothing stops a careless reader from doing this:
// let value = counter.count // unsynchronized read = raceLa concurrence de Swift change la donne
La concurrence de Swift fait de la sécurité contre les courses aux données une fonctionnalité du langage plutôt qu'une simple convention.
Trois outils coopèrent : actor pour protéger l'état mutable, Sendable pour les types pouvant être partagés en toute sécurité, et le compilateur pour faire respecter ces deux garanties.
actor Counter {
private var count = 0
func increment() { count += 1 }
}Les acteurs sérialisent les accès
Un acteur garantit qu'une seule tâche exécute son code de modification à la fois. L'environnement d'exécution sérialise automatiquement les accès.
Vous n'écrivez jamais de lock : le modèle des acteurs fournit la synchronisation.
actor BankAccount {
private(set) var balance = 0
func deposit(_ amount: Int) { balance += amount }
}Vérification à la compilation
Le compilateur refuse que vous accédiez à un état isolé par un acteur sans passer par cet acteur. Les appels entre acteurs deviennent asynchrones (await).
Les courses qui survenaient à l'exécution deviennent ainsi des erreurs de compilation.
let account = BankAccount()
// Must await: balance is actor-isolated
// let b = await account.balanceSendable délimite ce qui traverse les fils d'exécution
Le protocole Sendable marque les types qu'il est sûr de transmettre au-delà des frontières de concurrence.
Le compilateur bloque l'envoi d'un état mutable non conforme à Sendable vers une autre tâche, supprimant ainsi la course au niveau des types.
struct Money: Sendable {
let amount: Int
let currency: String
}Vérification rapide : courses aux données
Vérifiez votre compréhension des causes d'une course aux données.
Récapitulatif : le problème des courses aux données
Les courses aux données proviennent d'un état mutable partagé auquel on accède simultanément sans synchronisation, ce qui entraîne des mises à jour perdues, des déchirements et un comportement indéfini.
Les anciennes solutions, comme les lock et les files séquentielles, fonctionnent, mais elles ne sont pas vérifiées et restent fragiles. La concurrence de Swift remplace la convention par des mécanismes de contrôle : actor isole l'état, Sendable délimite ce qui traverse les frontières et le compilateur vérifie la sécurité. La suite de ce cours étudie ces outils en profondeur.
Questions Fréquemment Posées
La leçon « Le problème des courses de données » est-elle gratuite ?
Oui — le texte complet de « Le problème des courses de données » 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 Swift Academy, passe à CoddyKit PRO. Le cours Swift Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Le problème des courses de données » ?
Comprenez pourquoi les modifications concurrentes sont dangereuses. Tu pratiques Swift 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 Swift Academy ?
Aucune expérience préalable n'est requise. Swift 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 1 sur 4.
Combien de temps prend la leçon « Le problème des courses de données » ?
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 Swift Academy ?
Oui. Chaque leçon Swift 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
- Le problème des courses de données
- Le protocole Sendable
- Isolation des acteurs et nonisolated
- Migrer vers la concurrence stricte