../thread-and-gcd

Swift Thread and Grand Central Dispatch

Apple offers two ways for multitasking in iOS development: Grand Central Dispatch (GCD) and NSOperation. In this essay, we shall discuss GCD. If you need a review on the fundamentals of concurrency in iOS development, read this article.

GCD was introduced in iOS 4 and gives developers more freedom when using concurrency in their apps.

The basic goal of GCD is to bring thread management closer to the operating system. It abstracts threads away from the developer, reducing the number of details he must consider. In essence, GCD determines which thread will be used to complete a given task.

How it works?

GCD performs system-submitted tasks using closure queues. From Apple documentation, Queues, also known as dispatch queues, are objects that handle the execution of tasks either sequentially or concurrently.

GCD provides three type Queues :

  1. Main Queue : Serial
  2. Global Queue: Concurrent (Parallel)
  3. Custom Queue : Serial / Concurrent (Parallel)

When we create an application, a Main Thread is also created. It is associated with the application. The application contains only one main thread.

Main Queue runs on the Main Thread. If the main thread becomes blocked, the application will crash.

The main queue in GCD is serial, not concurrent. The main queue handles jobs serially, which means they are executed one at a time, in the order they were added to the queue.

GCD Main Queue
+------------+     +------------+    +------------+
|            |     |            |    |            |
|   Task 1   +---->|   Task 2   +--->|   Task 3   |
|            |     |            |    |            |
+------------+     +------------+    +------------+

DispatchQueue.main.async{
  // main thread will not get blocked
  // all UI update
}

DispatchQueue.main.sync{
  // main thread will block after task complete then release
}


Global Queue is a concurrent Queue that executes tasks based on the priority of task. the way we set up its importance is by using quality of service (Qos).

Four main types Qos and one is default.

  1. userInteractive
  2. userInitiated
  3. default
  4. utility
  5. background

userInteractive

userInteractive tasks that have a userinteactive quality of service run on the main thread. they execuated immediately to ensure great user experience.

let userInteractiveQueue = DispatchQueue.global(qos: .userInteractive)

userInteractiveQueue.async {
   // Perform a task that requires immediate user interaction
}

userInitiated

userInitiated often used for responsive user interactions and tasks that require timely responses.

let userInitiatedQueue = DispatchQueue.global(qos: .userInitiated)

userInitiatedQueue.async {
    // Perform a task initiated by the user that should complete quickly
}

default

default is commonly used for general-purpose tasks that don’t have specific QoS requirements. It represents a moderate priority level.

let defaultQueue = DispatchQueue.global(qos: .default)
defaultQueue.async {
    // Perform a task with default priority
}

utility

utility is used for tasks that are considered non-time-critical and can run in the background without impacting the user experience significantly. It is typically used for long-running or background tasks that are not high-priority.

let utilityQueue = DispatchQueue.global(qos: .utility)
utilityQueue.async {
    // Perform a background task with utility priority
    // api calling perform 
}

background

background is used for tasks that are considered low-priority and can run in the background without affecting the user experience. It’s typically used for long-running or non-critical background tasks that should not interfere with the responsiveness of the application.

let backgroundQueue = DispatchQueue.global(qos: .background)
backgroundQueue.async {
    // Perform a background task with low priority
    // like database vacuuming, maintenance
}

Custom Queue

Custom Queue can be either serial or concurrent. most oftern custom queues are execuated on a global queue.

In the absence of an attributes the custom queue will be a serial queue.

// Create a custom serial queue
let customSerialQueue = DispatchQueue(label: "serialQueue")
// Perform a task on the custom serial queue
customSerialQueue.async {
    print("Task 1 is running on the custom serial queue.")
}
// Perform another task on the same custom serial queue
customSerialQueue.async {
    print("Task 2 is running on the custom serial queue.")
}

Attributes are what define the behavior of the queue. When creating a custom queue, there are two major attributes to consider, with one option being to make the queue concurrent.

// let cq = DispatchQueue(label: "con", attributes: [.initiallyInactive, .concurrent])
// Create a custom concurrent queue
let customConcurrentQueue = DispatchQueue(label: "concurrentqueue", attributes: .concurrent)

// Perform tasks concurrently on the custom concurrent queue
customConcurrentQueue.async {
    print("Task 1 is running on the custom concurrent queue.")
}
customConcurrentQueue.async {
    print("Task 2 is running on the custom concurrent queue.")
}

What are async and sync?

Async (Asynchronous)

Sync (Synchronous)


In summary, while tasks submitted to global dispatch queues are assigned specific QoS classes that determine their priority, the system's thread pool manages the threads used to execute these tasks. Tasks in a specific QoS class may run on separate threads depending on system resource availability.

/swift/ /thread/ /multi-threading/