Showing posts with label gcd. Show all posts
Showing posts with label gcd. Show all posts

Saturday, December 4, 2021

iOS: QoS - Quality of service

The Quality of Service (QoS) class classifies what you want dispatchQueue to do. Indicates the importance of your app by specifying the quality of the task. When scheduling tasks, the system prioritizes tasks with higher service classes. Higher priority tasks are faster than lower priority tasks and are performed using more resources, which typically requires more energy than lower priority tasks. You can ensure your app's responsiveness and energy efficiency by specifying exactly the right QoS class for what your app does.

priority

userInteractive > userInitiated > default > utility > background


userInteractive

actions that interact with the user, such as working on the main thread, refreshing the user interface, or performing animations. focus on responsiveness and performance.

The task is almost instantaneous.


userInitiated

this class assigns it to tasks that provide immediate results for what the user is doing or prevent the user from using the app. for example, you can load the contents of the email that you want to display to the mercenary. you need immediate results, such as opening documents saved as user-initiated tasks,or performing tasks when a user clicks something in the user interface. work is required to continue user interaction. focus on responsiveness and performance.

Tasks like seconds or less are almost instantaneous.


default

The default quality of service class. Assign this class to a task or queue that your app starts or uses to perform active tasks on behalf of the user. This QoS is not used by developers to classify tasks. QoS is used as the default for unspecified operations and runs at the GCD global queue level.


utility

a quality of service class for tasks that are not actively tracked by the user. tasks that take time to complete and do not require immediate results, such as downloading or importing data. utility operations typically have progress bars that are visible to the user. it focuses on providing a balance between responsiveness, performance and energy efficiency.

The operation takes a few seconds to a few minutes.


background

tasks that work in the background and are not visible to the user, such as indexing, synchronization, and backup. focus on energy efficiency.

Tasks that take a considerable amount of time and require minutes or hours


unspecified

There are no quality of service classes. This indicates that there is no QoS information and signals that QoS should be inferred into the system. If a thread uses a legacy API, the thread can have unspecified QoS.

Reference:

iOS: GCD - Grand Central Dispatch



GCD is an API that performs parallelism programming or multithreading operations. In other words, the GCD API handles which tasks to do, one sequentially, multiple simultaneously, sync or Async. You can choose the right queue and QoS for your situation to improve execution efficiency.

Dispatch Queue


GCD provides Thread Safe one Dispatch Queue to perform Multi-threading operations. All Dispatch Queues are FIFO data structures. Therefore, the task always starts in the order in which it was added.

Serial(main)


Serial queues are serial queues that process them one by one in the order in which they were added to the queue. One Task must be completed to process the next Task.



Because all events related to the UI are attached to Main Thread, all UI operations must be performed on the Main Queue.

Concurrent(global)


Component queues are parallel queues that execute multiple operations at the same time. Task runs in the order in which they were added to the queue. The number of tabs that can be run at once is variable and depends on system conditions. Global Queue provides quality of service (QOS)for prioritizing tasks.


When sending tasks to global concurrent queues, they do not specify a direct priority. Instead, specify a Quality of Service (QOS) class property: this indicates the importance of the task and helps the GCD determine the priorities to assign to the task.

Sync, Async


Sync (synchronous)

After the thread registered with the queue is finished, run the next queue sequentially.


Async (asynchronous)

The threads registered in the queue do not wait until the end of the operation, and the next queue is run sequentially and simultaneously. The end of a task is not sequential and can vary from task to task. The difference is whether to wait until one task is completed and then run the next. In the case of Sync, you should use Async because you can't do anything if you use it if it takes a long time or you're uncertain when it's going to be done. Depending on which queue uses synchronous asynchronous, you can use it as follows:
  • Serial
    • Sync
    • Async
  • Concurrent
    • Sync
    • Async


Using Dispatch Queue


Create DispatchQueue

// Serial Queue
DispatchQueue.main.sync { } // CRASH!
DispatchQueue.main.async { }
DispatchQueue(label: "com.CustomSerialQueue").sync { }
DispatchQueue(label: "com.CustomSerialQueue").async { }

// Concurrent Queue
DispatchQueue.global().sync { }
DispatchQueue.global().async { }
DispatchQueue(label: "com.CustomConcurrentQueue", attributes: .concurrent).sync { }
DispatchQueue(label: "com.CustomConcurrentQueue", attributes: .concurrent).async { }
  






DispatchQueue.main.sync If you use , you will get an error. The reason for this is that if you sync to the main queue while working on the main queue and block it, you will fall into a deadlock. If you synchronise serial queues, you can create and use custom queues rather than main.


Serial queue - Sync

Because other tasks are blocked until the end of the queue's work, one operation must be completed before the other runs sequentially.

let serialQueue = DispatchQueue(label: "serialQueue")

serialQueue.sync {
  for i in 0...3{
    print("\(i) [serial_sync_1]")
  }
  print("--------------------------")
}

serialQueue.sync {
  for i in 0...5{
      print("\(i) [serial_sync_1]")
  }
  print("--------------------------")
}

for i in 0...5{
  print(i)
}


======== Result ========

0 [serial_sync_1]
1 [serial_sync_1]
2 [serial_sync_1]
3 [serial_sync_1]
--------------------------
0 [serial_sync_2]
1 [serial_sync_2]
2 [serial_sync_2]
3 [serial_sync_2]
--------------------------
0
1
2
3  


Serial queue - Async

Because it is a serial queue, the operations entered the queue are processed in order, although other operations are still processed by running the queue asynchronously.

let serialQueue = DispatchQueue(label: "serialQueue")

serialQueue.async {
  for i in 0...3{
    print("\(i) [serial_async_1]")
  }
  print("--------------------------")
}


serialQueue.async {
  for i in 0...3{
    print("\(i) [serial_async_2]")
  }
  print("--------------------------")
}

for i in 0...5 {
  print(i)
}


======== Result ========

0
0 [serial_async_1]
1
1 [serial_async_1]
2
2 [serial_async_1]
3
3 [serial_async_1]
4
--------------------------
0 [serial_async_2]
5
1 [serial_async_2]
2 [serial_async_2]
3 [serial_async_2]
--------------------------


Concurrent queue - Sync

In the serial queue, one operation must be completed, such as sync, before the other runs sequentially.

DispatchQueue.global().sync {
  for i in 0...3{
    print("\(i) [global_sync_1]")
  }
  print("--------------------------")
}

DispatchQueue.global().sync {
  for i in 0...3{
    print("\(i) [global_sync_2]")
  }
  print("--------------------------")
}

for i in 0...3 {
  print(i)
}


======== Result ========

0 [global_sync_1]
1 [global_sync_1]
2 [global_sync_1]
3 [global_sync_1]
--------------------------
0 [global_sync_2]
1 [global_sync_2]
2 [global_sync_2]
3 [global_sync_2]
--------------------------
0
1
2
3

Concurrent queue - Async

Because we process tasks simultaneously in parallel, we don't know what will start and end first.

DispatchQueue.global().async {
  for i in 0...3{
    print("\(i) [global_async_1]")
  }
  print("--------------------------")
}

DispatchQueue.global().async {
  for i in 0...3 {
    print("\(i) [global_async_2]")
  }
  print("--------------------------")
}

for i in 0...3 {
  print(i)
}

======== Result ========

0
0 [global_async_2]
0 [global_async_1]
1
1 [global_async_2]
1 [global_async_1]
2
2 [global_async_1]
3
2 [global_async_2]
3 [global_async_1]
3 [global_async_2]
--------------------------
--------------------------
Reference: