정의
💡 앱의 main thread나 background thread에서 순차적 혹은 동시에 실행할 일들을 관리하는 객체
- dispatch queue는 FIFO 데이터 구조
- dispatch queue는 순차적 혹은 동시에 일들을 수행한다
- dispatch queue에 있는 작업들은 시스템에서 관리하는 thread pool에서 실행된다!!!
- 하지만 시스템은 main thread를 나타내는 dispatch queue들의 실행만을 보장한다(즉, main thread에서의 실행만을 보장함)
- dispatch queues를 사용하면 호출자(caller)와 관련하여 비동기/ 동기식으로 임의의 코드 블럭을 수행할 수 있다
- dispatch queues은 앱에서 task를 비동기적으로 동시에 수행 할 수 있는 손쉬운 방법
cf) Queue의 종류
Serial
- 하나의 작업이 끝나야지만 다음 작업을 시작하는 큐
- 즉, 한번에 하나의 작업만 하는 큐
Concurrent
- 동시에 여러 작업들을 시작하는 것
- 그럼 아무거나 먼저 시작? → nono, 먼저 들어온 작업이 먼저 시작됨
dispatch Queue의 타입
Serial
- Serial Queue(Private dispatch queue)라고 불린다
- 큐에 추가된 순서대로 한번에 하나의 task를 실행한다 → 즉, 하나의 작업이 끝나야만 다른 하나의 작업이 시작된다
- 현재 실행중인 task는 dispatch queue에서 관리하는 고유한 쓰레드에서 실행된다
- serial은 하나의 thread로만 보내진다
- Serial queue는 종종 특정 자원에 대한 액세스를 동기화하는데 사용된다
- 필요한 만큼 Serial Queue를 작성할 수 있고 각 큐는 다른 모든 큐와 관련하여 동시에 작업한다 → 즉, Serial queues를 4개 작성하면 각 큐는 하나의 작업(taks)만 실행하지만, 최대 4개의 task각 각 큐에서 실행
Concurrent
- Concurrent queue(global Dispatch queue)라고 불린다
- 동시에 하나 이상의 task를 실행하지만 task는 큐에 추가된 순서대로 계속 시작된다 → 앞의 task들이 끝났는지의 여부에 상관없이 들어온 task를 실행
- concurrent는 여러 thread로 나뉘어진다
- 현재 실행중인 task는 dispatch queue에서 관리하는 고유한 쓰레드에서 실행된다
- 특정 시점에서 실행되는 정확한 task의 수는 가변적이며 시스템 조건에 따른다
GCD란?
💡 ios에서 멀티코어 프로세서에 코드를 동시에 실행시키게 해주는 프레임워크
- GCD에서는 하나의 작업단위인 Task를 Dispatch queue에 전달하기만 하면 나머지는 시스템이 알아서 처리하고 실행시켜 준다
- Task의 단위는 블록이나 DispatchWorkItem의 인스턴스 형태로 존재한다
- GCD는 시스템 레벨에서 구동된다
- GCD는 적절하고 균형있게 사용 가능한 시스템 자원을 어플리케이션에 분배하기 때문 →즉, GCD에 Task만 잘 전달하면 시스템이 알아서 thread를 배정해서 Task를 실행시켜준다!!
- GCD에서 Queue는 FIFO형태이고 GCD는 Queue에 전달된 Task에 Thread를 Queue의 특성에 맞게 배정한다
- DispatchQueue클래스에서 Task를 전달시킬 Queue는 기본적으로 두 종류
- 순차적으로 task를 실행시키는 queue(아마 Main dispatch queue)
- 동시에 task를 실행시키는 queue(아마 global dispatch queue)
Cocoa Application에서 제공하는 Queue
즉, 미리 만들어진 queue들
Main dispatch Queue
- 앱의 main thread에서 task를 실행하는, 전역적으로 사용가능한 serial Queue
- Main queue에 전달된 Task는 항상 Main thread에서 실행된다
- Serial queue이므로 하나의 작업(task)가 끝나야 다음 작업을 실행한다
- main dispatch queue는 앱의 실행루프와 함께 작동하여 큐에 있는 task의 실행을 실행루프에 연결된 다른 이벤트 소스의 실행과 얽힌다
Main dispatch queue 사용코드
- main은 타입 프로퍼티이다 → 즉, 타입 자체에 속한 프로퍼티
DispatchQueue.main.sync {
}
DispatchQueue.main.async {
}
Global dispatch Queue
- Concurrent Queue이다
- 동시에 하나 이상의 task를 실행하지만 task는 큐에 추가된 순서대로 계속 시작됨
- 실행 중인 task는 dispatch queue에서 관리하는 고유한 쓰레드에서 실행된다
Global dispatch queue 사용코드
- global은 함수로 qos를 파라미터로 받는다
DispatchQueue.global().async {
}
cf) qos란?
- quality of service로 중요도를 의미한다
- qos는 dispatchQueue에서 수행할 작업을 분류한다
- DispatchQos에 qosClass라는게 있게 있다
- DispatchQos.qosClass는 작업 실행을 위한 우선순위를 지정하는 클래스이다
- DispatchQos.QoSClass는 enum으로 구성되어있다
- qos 파라미터로 들어간건 DispatchQos.QoSClass이다(즉, enum의 case가 들어가진다)
- 작동시킬 QoS를 지정함으로써 중요도를 표시하고 시스템이 우선순위를 정하고 이에따라 스케쥴링함
Sync와 Async
Sync
- 하나의 작업에 대한 응답이 올때까지 기다린다
- 즉, 하나의 작업이 끝날때까지 기다린다 → 단일 작업에 관한 것
global()일때
- sync니까 global큐가 끝날때까지 다른 작업을 하지 않는다
func example() {
DispatchQueue.global().sync {
for i in 1...5 {
print(i)
}
print("==================")
}
for i in 100...105 {
print(i)
}
}
example()
Serial일때
func example2() {
let ramooQueue = DispatchQueue(label: "ramoo")
ramooQueue.sync {
for i in 1...5 {
print(i)
}
}
print("========================")
for i in 100...105 {
print(i)
}
}
main.sync
메인 큐에 이미 수행 중인 블락(코드)가 있는 상태에서 DispatchQueue.main.sync{}을 호출하여 Task를 전달하면, Deadlock이 발생한다!!
→ 당연함,,, 반드시 한가지 종류의 일만 할 수 있는 작업자인데 이 작업자가 이미 A에 관한 일하고 있는 상태에서 갑자기 이거 하지말고 B 일해! 하면 과부화걸림,,
Async
- 일단 큐에 작업을 추가하고 작업이 끝나기를 기다리지 않는다 + 다른 작업을 할수도 있다
- 요청에 대한 응답을 기다리지 않는다
global()
- 결과는 매번 실행할 때마다 다르다!!
- global은 앞의 작업의 완료의 유무에 상관없이 동시에 실행할 수 있으므로 ⭐️가 끝나지 않아도 🔥을 실행할 수 있다
func example3() {
DispatchQueue.global().async {
for i in 1...5 {
print("\(i)⭐️")
}
print("==================")
}
DispatchQueue.global().async {
for i in 200...205 {
print("\(i)🔥")
}
print("==================")
}
for i in 100...105 {
print("\(i)🌸")
}
}
serial
- 결과는 매번 실행할 때마다 다르다!!
- async이기 때문에 앞의 작업을 기다리지 않고 serial queue에 넣을 수 있다 하지만 serial queue는 순차적으로 실행되기 때문에 ⭐️가 끝난 다음에 🔥가 실행된다
func example4() {
let ramooQueue = DispatchQueue(label: "ramoo")
ramooQueue.async {
for i in 1...5 {
print("\(i)⭐️")
}
print("==================")
}
ramooQueue.async {
for i in 200...205 {
print("\(i)🔥")
}
print("==================")
}
for i in 100...105 {
print("\(i)🌸")
}
}
async&sync 그리고 concurrent&serial(총 정리!!)
async&sync → 작업을 보내는 시점에서 기다릴지 말지에 대해 다룬다
- async → 작업을 보내고 응답 안기다려
- sync → 작업을 보내고 응답 기다려
concurrent&serial → queue로 보내진 작업들을 여러개의 thread로 보낼 것인지인지 하나의 thread로 보낼 것인지
- concurrent → 여러 스레드로 보내
- serial → 하나의 스레드로 보내
- concurrent(global queue)와 async
- 메인 스레드의 작업 흐름이 태스크를 queue에서 넘기자마자 반환된다(async) → 즉, task의 작업이 끝났는지와 상관없이 queue가 task를 메인(혹은 기타) 스레드에 계속 넘긴다
- queue가 task를 넘길 때 하나의 스레드에만 넘기는 것이 아니라 다른 스레드에도 넘길 수 있고 여러 스레드들이 동시에 실행(concurrent)
- serial(main queue)와 async
- 메인 스레드의 작업 흐름이 태스크를 queue에서 넘기자마자 반환된다(async) → 즉, task의 작업이 끝났는지와 상관없이 queue가 task를 메인 스레드에 계속 넘긴다
- queue가 task를 메인스레드에 계속 넘겨도 메인스레드는 들어온 작업을 순차적으로 처리한다(serial)
- concurrent와 sync
- 메인 스레드의 작업 흐름이 queue에서 넘긴 task가 끝날때까지 멈춰있다(sync) → 즉, 메인스레드가 하나의 작업만 한다
- 현재 메인 스레드의 task말고 다른 스레드에서도 작업이 동시에 실행될 수 있으므로 큐에 있는 task들은 다른 스레드로 넘어간다(concurrent)
- serial(Main queue)와 sync
- 메인 스레드의 작업 흐름이 queue에서 넘긴 task가 끝날때까지 멈춰있다(sync) → 즉, 메인스레드가 하나의 작업만 한다
- queue에 있는 다른 task들은 메인 스레드에 있는 task가 다 끝나야지만 메인스레드로 넘어가서 실행될 수 있다(serial)
참고한 블로그
[iOS] 차근차근 시작하는 GCD — 4
[iOS] GCD (Grand Central Dispatch) 란? (feat. main & global dispatch queue)