/*:#localized(key: "SerialVsConcurrent")
 # Serial vs. Concurrent: order and overlap

 Every queue is either **serial** or **concurrent**, and the difference is
 the single most important thing to understand about queues.

 * A **serial queue** runs one closure at a time, to completion, in the order
 you added them (FIFO). No two of its tasks ever overlap. One barista, one
 ticket at a time.
 * A **concurrent queue** may run many of its closures at once, on several
 threads. It *starts* them in order, but they can finish in any order. Many
 baristas pulling tickets off the same rail.

 The main queue is serial. Global queues are concurrent. A custom queue is
 serial unless you opt into concurrency with `attributes: .concurrent`.

 Here's a **serial** custom queue keeping strict order:

 ```swift
 // Serial by default: one order finished before the next starts.
 let counter = DispatchQueue(label: "coffee-bar.serial")

 for order in 1...4 {
     counter.async {
         Thread.sleep(forTimeInterval: 0.2)  // brewing time
         print("Served order #\(order)")
     }
 }
 ```

 Run that on its own and the orders always print `1, 2, 3, 4`, in that order,
 every time. A serial queue is a promise: tasks run one after another, in the
 order submitted.

 Now run the same four orders on a **concurrent** queue below.
 */
//#-editable-code
import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

// Concurrent: several orders can brew at the same time.
let counter = DispatchQueue(label: "coffee-bar.concurrent",
                            attributes: .concurrent)

for order in 1...4 {
    counter.async {
        // Different orders take different times.
        Thread.sleep(forTimeInterval: Double.random(in: 0.1...0.4))
        print("Served order #\(order)")
    }
}

// The orders overlap, so we can't rely on any one finishing last.
// Instead, end the page after a fixed delay on the main queue.
DispatchQueue.main.asyncAfter(deadline: .now() + 1.4) {
    print("Closing the counter")
    PlaygroundPage.current.finishExecution()
}
//#-end-editable-code
/*:#localized(key: "SerialVsConcurrent-2")
 **Watch it run:** the order numbers come out **scrambled**: maybe `3, 1, 4,
 2` this time, something else next time. They *started* in order but ran in
 parallel and finished whenever their random brew time was up. This
 nondeterminism is real: run it a few times and you'll see different
 orderings. If your code ever depends on the order concurrent tasks finish
 in, that's a bug waiting to happen.

 * callout(Try it): Run it three times in a row. Do you ever get `1, 2, 3, 4`?
 Now delete `attributes: .concurrent` and run it three more times.

 [Previous](@previous)  |  page 5 of 9  |  [Next: The Return Trip: Hop Back to Main](@next)
 */
