NielJoubert
1/2/2018 - 9:06 AM

FIFO queues to explicitly control execution order

typealias Block = () -> Void
typealias Queue = [Block]

var fastQueue = Queue()
var slowQueue = Queue()
let scheduleQueue = DispatchQueue(label: "schedule")
let workQueue = DispatchQueue(label: "work")
let lock = DispatchGroup()

func scheduleSlow(block: @escaping Block) {
    scheduleQueue.async {
        slowQueue.insert(block, at: 0)
        scheduleQueue.async() {
            next()
        }
    }
}

func scheduleFast(block: @escaping Block) {
    scheduleQueue.async {
        fastQueue.insert(block, at: 0)
        scheduleQueue.async() {
            next()
        }
    }
}

private func next() {

    lock.wait()

    guard let block = fastQueue.popLast() ?? slowQueue.popLast() else {
        // Nothing to do
        return
    }

    lock.enter()
    workQueue.async {
        block()
        lock.leave()
    }
}

workQueue.suspend()

var buffer = [String]()
let group = DispatchGroup()

for i in 0 ..< 10 {
    
    group.enter()
    scheduleSlow {
        for i in 0 ..< 1_000_000 {
        }
        buffer.append("slow #\(i)")
        group.leave()
    }

    group.enter()
    scheduleFast {
        for i in 0 ..< 1_000_000 {
        }
        buffer.append("fast #\(i)")
        group.leave()
    }
}

workQueue.resume()
group.wait()
print(buffer.joined(separator: "\n"))