/*:#localized(key: "Overview")
 # Groups and Semaphores

 Back at the corner coffee bar, a customer orders a batch for the whole office:
 a latte, a cold brew, and an espresso. You fire off all three at once so they
 brew in parallel. Good. But now you have a new problem. You can only hand the
 tray to the customer when **all three** are ready, and each one finishes at its
 own time. How does your code *know* the batch is complete? And what happens when
 five baristas want the one espresso machine at the same moment? This chapter is
 about coordinating a group of independent tasks: waiting for all of them, and
 limiting how many run at once.

 ---
 
 ## What you'll learn

 * How to wait for a whole batch of async tasks with a **`DispatchGroup`**.
 * The `enter()`/`leave()` balance, `notify(queue:)`, and `wait()`, and why
 `wait()` blocks.
 * The classic unbalanced-`enter`/`leave` bug, and how it hangs or crashes.
 * How a **`DispatchSemaphore`** limits how many tasks touch a resource at once.
 * When to reach for a group versus a semaphore.

 This chapter builds on the chapter [GCD Fundamentals](GCD%20Fundamentals.playgroundchapter/Overview): you already know how to push work onto a
 queue with `async`, and the difference between serial and concurrent queues.
 Now you'll coordinate that work.

 When you're ready, turn the page and  we'll fire off a batch of drinks the
 naïve way, and watch it go wrong.

 page 1 of 8  |  [Next: The Problem: Knowing When Everything Is Done](@next)
 */
