GCD에 대해 알아보기 (Dispatch Queue)
이번 포스트에서는 GCD에 대해 알아보도록 하겠습니다. GCD는 Grand Central Dispatc의 약자로 대표적으로 Dispatch Queue라는 것이 있습니다. GCD는 멀티 스레드를 구현하기 위해 Apple에서 제공하는 API 입니다.
Dispatch Queue
Dispatch Queue는 응용 프로그램이 블록 개체 형태로 작업을 제출할 수있는 FIFO 큐입니다. Dispatch Queue는 작업을 직렬 또는 동시에 실행합니다. Dispatch Queue에 제출 된 작업은 시스템이 관리하는 스레드 풀에서 실행됩니다. 앱의 메인 스레드를 나타내는 Dispatch Queue를 제외하고 시스템은 작업을 실행하는 데 사용하는 스레드를 보장하지 않습니다.
작업 항목을 동기식 또는 비동기식으로 스케줄합니다. 작업 항목을 동기식으로 스케줄하면 코드는 해당 항목의 실행이 완료 될 때까지 대기합니다. 작업 항목을 비동기 적으로 예약하면 작업 항목이 다른 곳에서 실행되는 동안 코드가 계속 실행됩니다.
Dispatch Queue는 2가지 종류로 나눌수 있습니다.
Serial Dispatch Queue와 Concurrent Dispatch Queue입니다.
- Serial Dispatch Queue
Serial Queue는 등록된 작업을 한번에 하나씩 차례대로 처리 합니다.
처리중인 작업이 완료되면 다음 작업을 처리합니다.
- Concurrent Dispatch Queue
Concurrent Queue는 등록된 작업을 한번에 하나씩 처리 하지 않고
여러 작업들을 동시에 처리합니다.
let serialQueue = DispatchQueue(label: "denny.k.serial")
print(serialQueue) // Serial Dispatch Queue
let concurrentQueue = DispatchQueue(label: "denny.k.concurrent", attributes: .concurrent)
print(concurrentQueue) // Concurrent Dispatch Queue
앱 실행시 시스템에서 기본적으로 2개의 Queue를 만들어 줍니다.
Main Queue와 Global Queue 입니다.
- Main Queue
메인 스레드(UI 스레드)에서 사용 되는 Serial Queue 입니다. 모든 UI 처리는 메인 스레드에서 처리를 해야 합니다.
- Global Queue
편의상 사용할수 있게 만들어 놓은 Concurrent Queue 입니다. Global Queue는 처리 우선 순위를 위한 qos(Quality of service) Parameter를 제공합니다. 병렬적으로 동시에 처리를 하기때문에 작업 완료의 순서는 정할수 없지만 우선적으로 일을 처리하게 할수 있습니다.
let mainQueue = DispatchQueue.main
print(mainQueue) // Main Queue
let globalQueue = DispatchQueue.global(qos: .background)
print(globalQueue) // Global Queue
QOS의 Priority는 다음과 같습니다.
userInteractive
userInitiated
default
utility
background
unspecified
sync / async
Dispatch Queue는 sync와 async라는 메소드를 가지고 있습니다.
동기, 비동기라는 말을 많이 들어 보셨을 겁니다. sync는 동기 처리 메소드 입니다.
해당 작업을 처리하는 동안 다음으로 진행되지 않고 계속 머물러 있습니다.
DispatchQueue.main.sync {
print("value: 1")
}
print("value: 2")
// 결과
/*
value: 1
value: 2
*/
async는 비동기 처리 메소드 입니다.
sync와는 다르게 처리를 하라고 지시후 다음으로 넘어가 버립니다.
let globalQueue = DispatchQueue.global(qos: .background)
globalQueue.async {
print("value: 1")
}
print("value: 2")
// 결과
/*
value: 2
value: 1
*/
보통 스레드 처리를 하는 작업들은 시간이 꽤나 걸리는 큰 작업이거나 언제 끝날지 알수 없는 작업에 사용 되는데 (ex: 네트워크, 파일로딩) 작업이 처리 되는동안 아무것도 하지 못하고 멈춰 있으면 앱이 렉이 걸리거나 아무 반응이 없는거처럼 보입니다. 그래서 보통 동기 처리 메소드인 sync는 잘 사용하지 않습니다.