Chapter 1 — Introduction: what concurrency really is
Concurrency is about dependencies, not threads
flowchart LR
subgraph SEQ__Sequential__slow___ [\"Sequential (slow)\"]
T1[toast: 3 min] --> C1[coffee: 4 min] --> E1[egg: 3 min]
end
subgraph CON__Concurrent__fast___ [\"Concurrent (fast)\"]
T2[toast: 3 min]
C2[coffee: 4 min]
E2[egg: 3 min]
T2 --> B2[butter toast]
end
- Concurrency is dealing with many things at once — structuring a program so independent work can
- Parallelism is doing many things at once — literally executing on multiple cores simultaneously
Why the old way was so painful
Threads (the raw metal)
Grand Central Dispatch (queues)
// The GCD era — functional, but full of traps.
DispatchQueue.global().async {
let data = loadData() // background work
DispatchQueue.main.async { // hop back to the main thread for UI
self.label.text = data.title
}
}
- Callback pyramids. Every asynchronous step is a nested closure. Three sequential network calls
- No enforced structure. Nothing connects the background work to the UI hop. If the background
- No safety net for data races. GCD will happily let you touch
self.itemsfrom two queues at
flowchart TB
A["loadUser { user in"] --> B[" loadPosts(user) { posts in"]
B --> C[" loadComments(posts) { comments in"]
C --> D[" DispatchQueue.main.async { update UI }"]
D --> E[" } // and error handling in each level…"]
Modern Swift concurrency (async/await, 2021→)
async/awaitlets asynchronous code read like straight-line code. The three-call pyramid- Structured concurrency ties child work to a scope with automatic waiting and cancellation, so
- Actors,
Sendable, and Swift 6 checking make data races a compile-time error. The category
The three ideas this book is built on
flowchart LR
I1["await = maybe suspend
(not block a thread)"] --> BOOK I2["structured concurrency
= work bound to scope"] --> BOOK I3["isolation + Sendable
= who touches what"] --> BOOK["A model you can
reason about"]
(not block a thread)"] --> BOOK I2["structured concurrency
= work bound to scope"] --> BOOK I3["isolation + Sendable
= who touches what"] --> BOOK["A model you can
reason about"]
What a "data race" actually is
- two or more pieces of code access the same memory concurrently,
- at least one of those accesses is a write, and
- there's no synchronization ordering them.
What this book covers, and what it assumes
- Part I —
async/await, theTasktype, and cancellation. After this you can write and run - Part II — structured concurrency (
async let, task groups), continuations (to bridge the old - Part III — actors (safe shared state), their reentrancy pitfall, the main actor and global
- Part IV — turning on Swift 6's strict checking and fixing what it finds, Swift 6.2's
A note on mindset
What we set up in this chapter
- Reframed concurrency as describing dependencies between pieces of work, distinct from parallelism
- Traced the three eras — threads → GCD → async/await — and named the chronic problems of the old
- Introduced the three ideas the book is built on:
awaitis a possible suspension, not a block; - Defined the enemy precisely — a data race (concurrent access, at least one write, no
- Set the mindset: the Swift 6 compiler is a collaborator, and its diagnostics are lessons, not
Mental model to take away
- Concurrency is structure, not threads. You describe what can overlap and what must wait; the
- The old tools let you write the bug; modern Swift is designed so the bug doesn't compile.
- Hold three ideas above everything:
awaitmay suspend (not block), **structured concurrency ties - A data race — the defining hazard — is exactly what Swift 6 eliminates at compile time. Treat its