Concurrency means that an application is making progress on more than one task at the same time (concurrently). If the computer only has one CPU, then the application may not make progress on more than one task at exactly the same time, but more than one task is being processed at a time inside the application using the technique called context switching. It doesn’t completely finish one task before it begins the next.
Parallelism is the notion of multiple things happening at the same time (no context switching).
Grand Central Dispatch or GCD is a low-level API for doing Concurrency / Parallelism in your application.
GCD under the hood manage a shared thread pools and add optimal number of threads in that pool. With GCD you add blocks of code or work items to queues and GCD decides which thread to execute them on. GCD executes this task either concurrently or parallely depending upon the system physical condition or current load.
In the past we do concurrency using manually creating threads. We create a thread on some core and give the task to run. Threaded solutions is a low level solutions and must be managed manually.
- It’s developer responsibility to decide optimal number of threads for an application because if you create thousands of threads most of the time it will do context switching instead of doing actual work Optimal number of threads for an application can change dynamically based on the current system load.
- Synchronization mechanisms typically used with threads add complexity
- It’s developer or application responsibility to make use of the extra cores more effectively.
- Number of cores that can be used efficiently, which is a challenging thing for an application to compute on its own.
All you have to do is define the tasks you want to execute concurrently and add them to an appropriate dispatch queue. GCD takes care of creating the needed threads and of scheduling your tasks to run on those threads
Dispatch queues are a C-based mechanism for executing custom tasks. Dispatch queue always dequeues and starts tasks in the same order in which they were added to the queue.) Dispatch queues are thread-safe which means that you can access them from multiple threads simultaneously. Dispatch Queue is not Thread
If you want to perform concurrent task through GCD you add them to an appropriate dispatch queue. GCD will pick the task and execute them on the basic of the configuration done on the dispatch queues.
Dispatch queue is the core of the GCD. On the basis of Dispatch queues configuration GCD pick and execute concurrent tasks.
Main queue: runs on the main thread and is a serial queue.
Global queues: concurrent queues that are shared by the whole system. There are four such queues with different priorities : high, default, low, and background.
Custom queues: queues that you create which can be serial or concurrent. Requests in these queues actually end up in one of the global queues.
When sending tasks to the global concurrent queues, you don’t specify the priority directly. Instead, you specify a Quality of Service (QoS) class property. This indicates the task’s importance and guides GCD in determining the priority to give to the task.
Example to create above said queues:
let mainQueue = DispatchQueue.main let globalQueue = DispatchQueue.global let custom = DispatchQueue(label: String, qos: DispatchQoS,attributes: DispatchQueue.Attributes,autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency, target: DispatchQueue?)
label: This is a string label that is attached to the queue to uniquely identify it in debugging tools, such as instruments and crash reports. It is recommended that we use a reverse DNS naming convention. This parameter is optional and can be nil.
attributes: This specifies the type of queue. Like DISPATCH_QUEUE_SERIAL, DISPATCH_QUEUE_CONCURRENT. If the this parameter is nil, a serial queue will be created.
qos: Quality of services. Types are User-interactive,User-initiated, Utility, Background. Higher the priority, higher will be the allocation of resources to that queue.
AutoreleaseFrequency: It has different options. Like:inherit, workitem, never
User-interactive: This represents tasks that must complete immediately in order to provide a nice user experience. Use it for UI updates, event handling and small workloads that require low latency. The total amount of work done in this class during the execution of your app should be small. This should run on the main thread.
User-initiated: The user initiates these asynchronous tasks from the UI. Use them when the user is waiting for immediate results and for tasks required to continue user interaction. They execute in the high priority global queue.
Utility: This represents long-running tasks, typically with a user-visible progress indicator. Use it for computations, I/O, networking, continuous data feeds and similar tasks. This class is designed to be energy efficient. This will get mapped into the low priority global queue.
Background: This represents tasks that the user is not directly aware of. Use it for prefetching, maintenance, and other tasks that don’t require user interaction and aren’t time-sensitive. This will get mapped into the background priority global queue.
With GCD, you can dispatch a task either synchronously or asynchronously.
A synchronous function returns control to the caller after the task completes. You can schedule a unit of work synchronously by calling
An asynchronous function returns immediately, ordering the task to start but not waiting for it to complete. Thus, an asynchronous function does not block the current thread of execution from proceeding on to the next function. You can schedule a unit of work asynchronously by calling