Das Data-Race-Problem
Verstehen Sie, warum nebenläufige Änderungen unsicher sind.
Das Data-Race-Problem ist eine kostenlose Swift Academy-Lektion auf CoddyKit. Dies ist Lektion 1 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Swift Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Swift Academy-Kurs umfasst insgesamt 4 Lektionen.
Was ist eine Data Race?
Eine Data Race tritt auf, wenn zwei oder mehr Threads gleichzeitig auf denselben Speicherbereich zugreifen, mindestens einer dieser Zugriffe ein Schreibzugriff ist und keine Synchronisierung zwischen ihnen stattfindet.
Das Ergebnis ist undefiniertes Verhalten: beschädigte Werte, Abstürze oder Fehler, die erst unter Last auftreten.
Gemeinsam genutzter veränderlicher Zustand
Die Ursache von Data Races ist ein gemeinsam genutzter veränderlicher Zustand. Wenn mehrere Tasks dieselbe Variable lesen und schreiben können, wird die Reihenfolge unvorhersehbar.
Der Zähler unten kann Inkremente verlieren, weil count += 1 aus Lesen, Ändern und Schreiben besteht und nicht atomar ist.
final class Counter {
var count = 0
func increment() {
count += 1 // read, add, write: not atomic
}
}Warum Inkremente verloren gehen
Die Anweisung count += 1 wird in drei Schritte übersetzt: Wert laden, eins addieren und den Wert zurückschreiben.
Wenn zwei Threads gleichzeitig 5 laden, schreiben beide 6, und ein Inkrement geht verloren.
// Thread A loads 5
// Thread B loads 5
// Thread A stores 6
// Thread B stores 6 <-- lost updateTearing bei größeren Werten
Neben verlorenen Aktualisierungen können gleichzeitige Schreibzugriffe auf Werte aus mehreren Wörtern, etwa eine Struct oder einen 64-Bit-Wert auf manchen Plattformen, zu Tearing führen: Ein Leser sieht die Hälfte eines Schreibvorgangs und die Hälfte eines anderen.
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 anotherDie alte Lösung: Locks
Vor Swift Concurrency war ein Lock (Mutex) die klassische Lösung. Immer nur ein Thread hält gleichzeitig das Lock, wodurch die Zugriffe serialisiert werden.
Locks funktionieren, sind aber leicht falsch einzusetzen: vergessene Entsperrungen, Deadlocks und Prioritätsumkehr.
import Foundation
final class SafeCounter {
private let lock = NSLock()
private var count = 0
func increment() {
lock.lock()
defer { lock.unlock() }
count += 1
}
}Serielle Dispatch-Queues
Ein weiterer klassischer Ansatz ist eine serielle Dispatch-Queue. Alle Änderungen werden über eine Queue geleitet, sodass sie sich niemals überschneiden.
import Foundation
final class QueueCounter {
private let queue = DispatchQueue(label: "counter")
private var count = 0
func increment() {
queue.async { self.count += 1 }
}
}Warum manuelle Synchronisierung fehleranfällig ist
Locks und Queues beruhen auf Disziplin. Der Compiler überprüft nicht, ob jeder Zugriff geschützt ist.
Ein einziger ungeschützter Lesezugriff reicht aus, damit die Race Condition zurückkehrt. Eine Garantie zur Compile-Zeit gibt es nicht.
// Nothing stops a careless reader from doing this:
// let value = counter.count // unsynchronized read = raceSwift Concurrency verändert die Spielregeln
Swift Concurrency macht die Sicherheit vor Data Races zu einem Sprachfeature statt zu einer Konvention.
Drei Werkzeuge arbeiten dabei zusammen: actor für geschützten veränderlichen Zustand, Sendable für sicher teilbare Typen und der Compiler, der beides durchsetzt.
actor Counter {
private var count = 0
func increment() { count += 1 }
}Actors serialisieren Zugriffe
Ein Actor garantiert, dass immer nur ein Task gleichzeitig seinen verändernden Code ausführt. Die Runtime serialisiert die Zugriffe automatisch.
Sie schreiben niemals ein Lock; das Actor-Modell übernimmt die Synchronisierung.
actor BankAccount {
private(set) var balance = 0
func deposit(_ amount: Int) { balance += amount }
}Durchsetzung zur Compile-Zeit
Der Compiler verhindert, dass Sie auf Actor-isolierten Zustand zugreifen, ohne über den Actor zu gehen. Aufrufe zwischen Actors werden asynchron (await).
Dadurch werden Laufzeit-Race-Conditions zu Fehlern zur Compile-Zeit.
let account = BankAccount()
// Must await: balance is actor-isolated
// let b = await account.balanceSendable begrenzt, was Threads überschreiten darf
Das Protokoll Sendable kennzeichnet Typen, die sicher über Nebenläufigkeitsgrenzen hinweg übergeben werden können.
Der Compiler verhindert, dass veränderlicher Zustand ohne Sendable an einen anderen Task gesendet wird, und verhindert die Race Condition damit auf Typebene.
struct Money: Sendable {
let amount: Int
let currency: String
}Kurze Überprüfung: Data Races
Testen Sie Ihr Verständnis davon, wodurch eine Data Race verursacht wird.
Zusammenfassung: Das Problem der Data Race
Data Races entstehen, wenn gleichzeitig und ohne Synchronisierung auf gemeinsam genutzten veränderlichen Zustand zugegriffen wird. Die Folgen sind verlorene Aktualisierungen, Tearing und undefiniertes Verhalten.
Alte Lösungen wie Locks und serielle Queues funktionieren, werden aber nicht überprüft und sind fehleranfällig. Swift Concurrency ersetzt Konventionen durch Durchsetzung: actor isoliert Zustand, Sendable begrenzt, was Grenzen überschreiten darf, und der Compiler überprüft die Sicherheit. Im weiteren Verlauf dieses Kurses untersuchen Sie diese Werkzeuge ausführlich.
Häufig gestellte Fragen
Ist die Lektion „Das Data-Race-Problem“ kostenlos?
Ja — der vollständige Text von „Das Data-Race-Problem“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Swift Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Swift Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Das Data-Race-Problem“?
Verstehen Sie, warum nebenläufige Änderungen unsicher sind. Du übst Swift Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Swift Academy zu starten?
Keine Vorkenntnisse erforderlich. Swift Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 1 von 4.
Wie lange dauert die Lektion „Das Data-Race-Problem“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Swift Academy-Lektion Code schreiben und ausführen?
Ja. Jede Swift Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Das Data-Race-Problem
- Das Sendable-Protocol
- Actor-Isolation und nonisolated
- Auf Strict Concurrency migrieren