/ Swift

Concurrency model in Swift

So you want to learn concurrency, but you don't know anything about threads or tasks? In this article I'm going to teach you everything with an extraordinary analogy.

The post was inspired by this song (metal fans ftw!)

Let's go party!

Imagine a fancy night club with multiple entrances and a bouncer on each entrance. The entrances are threads. Each thread has an associated bouncer aka. runloop. The runloop does nothing (sleeps) if there are no people coming to the entrance. Obviously each individual person is a single task to handle.

Nightclub = CPU (big gray box)
Person = Task (little gray circles)
Bouncer = Runloop (black circles)
Entrance = Thread (dark gray rectangles)
VIP queue = Main queue (VIP)
Priority queue = Priority background queue (A)
Regular queues = Regular background queues (B)

In order to make the entry process faster, clubs started to organize pre-made queues for their guests. Usually there is a VIP queue (main) and there can be other queues - like a priority queue for "not so very, but" important guests (A) - and one queue for the regular people (B).

If you wan't to do some crazy stuff or get noticed by the others you have to get through the VIP queue. You are allowed to do more in the VIP queue, like you can have unlimited drinks, or you can be a complete jerk, bouncers will still ignore you if you don't piss off the others too much.

Let me rephrase this: you can ONLY do UI modifications from the main queue, but if you block the queue with some really stupid - long taking - operation, your ass will be kicked because you stopped the whole application.

That's it. Now you know everything. Let's go & check out the tools that are available for you to develop a non-blocking application.

Grand Central Dispatch

GCD is the guy on the corner who will decide which queue can you join (it's like a face check). Nothing more. It'll just send you to a queue. Obviously if he sends you to the priority queue because you are a hot chick, you still can use either of the entrances, but in most of the cases you'll go to the less crowded one. GCD can't bring you to the front of the queue, you have to wait to get in to the club.

Ok, i'm done with the analogy. Seriously.

Execute code concurrently on multicore hardware by submitting work to dispatch queues managed by the system.

So this means that you can send piece of codes to queues managed by the system, using GCD like this:

DispatchQueue.global(qos: .background).async {
    print("This is going to run on a background queue")
}

DispatchQueue.main.async {
    print("This is going to run on the main queue")
}

DispatchQueue(label: "concurrent", attributes: .concurrent).sync {
    print("This is going to run on a concurrent queue")
}

DispatchQueue(label: "serial").sync {
    print("This is going to run on a serial queue")
}

You can use system provided queues or create your own ones. Those can be serial or concurrent and you can also execute tasks synchronously or asynchronously. Please read the official documentation made by Apple, that'll help you a lot to have a better understanding.

Queues & Operations

A queue that regulates the execution of a set of operations.

Well, if you read the docs it's pretty straightforward. A queue is just a queue exactly like the queue of people at the DMV. Actually operations - induviduals & their motivations aka. tasks - inside the queue are way more interesting.

OperationQueue.main.addOperation {
    print("This is going to run on the main queue")
}
OperationQueue().addOperation {
    print("This runs on my custom queue")
}

You know to be honest, operation helper classes are built on top of GCD with a little extra overhead, but for this price you can define dependencies and many other neat things to control your flow. I don't want to get too much into the details, there are many good articles about how to create operations, but I'd like to emphasize one little thing: how to pass data between two operationss? I linked the answer, but as always you should read the whole article. Hint: a third operation

Thread

Thread is just a wrapper class around pthreads. You have to be careful if you are planning to use thread objects. Please always use operations and queues or instead of the thread class. If you want to know why, here and here you can find the proper answers, but if you don't want to read that much:

In general you'll get better mileage with NSOperationQueue.

So again, avoid using threads, go with GCD & operations.

RunLoop

What the heck is a runloop? In my previous article I had a short explanation about event loops. An event loop is simply a runloop. It's a cycle that waits for incoming inputs or tasks to handle. Like a bouncer. He'll enter or "execute" people if they don't behave. Let me give you an advice: first you have to understand runloops & threads before you start using them. If you want to animate cells you are probably going to use a CADisplayLink & you're going to add that to a run loop, but for any other concurrent task: use operations & GCD!

Final takeaway: read more about concurrency. Recently some really amazing articles have born and I hope this trend will continue. Here are some of them: