study record

[iOS] 왜 GCD(Grand Central DispatchQueue)를 사용하는가? 본문

iOS/iOS 정리

[iOS] 왜 GCD(Grand Central DispatchQueue)를 사용하는가?

asong 2022. 3. 7. 22:11

GCD란?

멀티코어와 멀티 프로세싱 환경에서 최적화된 프로그래밍을 할 수 있도록 애플이 개발한 기술.

 

언제 GCD를 사용하게 되는가?

이벤트들을 비동기적으로 처리하지 않으면 메인 스레드에서 데이터를 가져오고 기다렸다가 UI를 업데이트하며 지연이 발생할 수 있다. 데이터베이스에서 데이터를 한번에 지연없이 가져올 수 없는 경우가 발생하기 때문이다. 이렇게 되면 데이터를 가져올 때까지 UI update도 늦어지게 된다. 이러한 경우를 해결하기 위해 GCD를 사용하게 된다. 뿐만 아니라 네트워킹, 이미지 프로세싱 등 많은 작업을 메인 스레드에서 모두 진행하게 되면 User Interface의 대응이 느려지거나 중지가 되기 때문이다.

 

GCD는 비동기 Queue(Dispatch Queue)를 생성하고, 데이터를 GCD Queue에서 가져온다. 비동기적으로 처리되기 때문에 메인 스레드에서 해야 하는 작업이 줄어들게 된다. 따라서 GCD라는 Concurrency Library를 사용해 메인 스레드의 일을 줄여야 한다.

 

Dispatch Queue

말그대로 Queue의 기능을 수행한다. 프로그래머의 작업(task)들을 운영체제의 관리 하에 비동기적으로 수행한다. 디스패치큐에 작업들을 추가하면 GCD는 테스크에 맞는 스레드를 자동으로 생성해서 실행하고 작업이 종료되면 해당 스레드를 제거하는 형식으로 수행한다.

 

Dispatch Queue 2가지 종류

  • Serial 디스패치 큐 : 한 번에 하나의 작업만 실행. 해당 작업이 완료 후 대기열에서 제외되고, 새로운 작업이 시작되기 전까지 기다려야 한다.
  • Concurrent 디스패치 큐 : 기다리지 않고 많은 작업을 동시에 실행한다.
// Serial Dispatch Queue
let serialQueue = DispatchQueue(label: "com.example.serial")
serialQueue.async {
    for i in 0..<10 {
        print("hi", i)
    }
}
serialQueue.async {
    for i in 100..<110 {
        print("hello", i)
    }
}

// Concurrent Dispatch Queue
let concurrentQueue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent)
concurrentQueue.async {
    for i in 0..<10 {
        print("hi", i)
    }
}
concurrentQueue.async {
    for i in 100..<110 {
        print("hello", i)
    }
}

앱 실행 시에 시스템에서 기본적으로 2개의 큐를 제공한다.

메인 스레드(Main Queue) : 메인 스레드(UI Thread)에서 사용되는 Serial Queue이다. 

글로벌 큐(Global Queue) : 편의상 사용할 수 있게 만들어 놓은 Concurrent Queue이다. 전체 시스템에서 공유가 되고, 처리할 우선순위를 정하기 위해 QoS 매개변수를 제공한다. 병렬적으로 동시에 처리하므로 완료 순서는 모르지만 우선적으로 일을 처리하게 할 수 있다.

 

QoS

QoS는 Quality Of Service의 약자이다. 시스템은 QoS 정보를 사용하여 우선순위를 조정하게 된다. 이를 통해 작업 성능(Performance)와 에너지 효율성을 챙길 수 있다.

let serialQueue1 = DispatchQueue(label: "com.example.serial1", qos: .background)
let serialQueue2 = DispatchQueue(label: "com.example.serial2", qos: .userInteractive)

QoS의 종류는 다음과 같다.

  • User-interactive
  • User-initiated
  • Utility
  • Background

User-interactive

사용자와 상호작용하는 작업이다. 메인 스레드에서 작동할, 사용자 인터페이스, 애니메이션을 수행한다. 작업이 빠르게 수행되지 않으면 UI 사용자 인터페이스가 멈춘 것처럼 보일 수 있기에 반응성과 성능에 중점을 둔다.

 

User-initiative

사용자가 시작하고 즉각적인 결과가 필요한 작업이다. 무언가를 클릭할 때, 저장된 문서를 여는 등 반응성과 성능에 중점을 둔다.

 

Utility

작업을 완료하는 데 시간이 약간 걸리며 즉각적인 결과가 필요하지 않은 작업이다. 데이터 가져오기, 다운로드의 작업이 속한다. 유틸리티 작업은 사용자가 볼 수 있는 진행상황(프로그래스바)을 가질 수 있다. 

 

Background

백그라운드에서 동작하며 사용자가 볼 수 없는 작업, 동기화, 백업 등이 속한다. 에너지 효율성에 중점을 둔다.

 

+Serial 과 Concurrent 는 한번에 하나만 처리하느냐 동시에 여러개 처리하느냐고, Sync/ Async는 처리가 끝날때까지 기다리느냐 지시 후 다른 처리를 하느냐에 초점이 맞춰져 있다.

DispatchQueue.main.async {
   print("async")
 }
    
let globalQueue = DispatchQueue.global(qos: .background)
globalQueue.async {
  print("value: 1")
}

 

참고 : 

https://velog.io/@heunb/GCD-Pt.1

https://github.com/YoungjunGu/Youngjun-iOS-Studio/blob/master/ConcurrencyProg/iOS-%EB%8F%99%EC%8B%9C%EC%84%B1%EC%A0%9C%EC%96%B4.md