iOS) GCD - Dispatch Queue

Havi·2020년 9월 14일
0

본 블로그는 개인적인 공부 및 저장의 용도 작성됐습니다.

GCD란

저수준의 쓰레드를 제어하기는 아주 어렵다. 따라서 쓰레드를 직접 생성하는 것이 아닌 GCD를 이용해 작업을 스케쥴하고, 이는 자원의 효율적 사용으로 이어진다. 즉 쓰레드의 생성과 관리를 개발자가 관리하는 것이 아니라 시스템이 관리하도록 한다.

GCD의 큰 장점 중 하나는 하드웨어의 자원을 걱정하지 않아도 된다는 점이다. GCD는 쓰레드 풀을 관리해준다.

Dispatch Queue는 FIFO로 시작한다. 하지만 끝나는 시간은 보장되지 않는다.

우리가 흔히 쓰는 GCD는
1. main dispatch queue (serial, pre-defined)
2. global queues (concurrent, pre-defined)
3. private queues (serial or concurrent, 우리가 만든 큐)

Main queue는 Main Thread에서 동작하는 serial queue로 UI를 그리고, 유저 인터렉션을 담당한다. 이 큐를 너무 오래 블록하면 앱이 freeze한다.

따라서 오래걸리는 작업(네트워크 콜, 무거운 연산 등)은 백그라운드 큐에서 돌린다.

private queues를 만들 때에는 descriptive label을 만들면 디버깅할 때 좋다. private queues는 default로 serial이고, 바꾸려면 attribute를 바꿔주면 된다.

sync vs async

sync를 걸면 현재 큐는 task가 끝나기 전까지 큐를 block한다. async는 현재 큐를 비동기적으로 돌려 control block을 리턴하고, async 클로저를 기다릴 필요없이 동작한다.

이 밑에는 옛날에 정리한 내용

멀티 쓰레딩을 위한 API에는

1.C 기반의 저수준 API인 GCD
2. Obj-C 기반의 고수준 API인 Operation

이 있음

OperationQueue 를 보려면 클릭

GCD (Grand Central Dispatch)

  • 멀티코어 환경에서 최적화된 프로그래밍을 지원하도록 애플이 개발한 기술
  • Queue이기 때문에 기본적으로 FIFO 방식을 따름

Dispatch Queue의 종류

  1. Serial (직렬 큐) : 한번에 하나의 일만 함
  2. Concurrent (동시 큐) : 동시에 여러 개의 일을 병렬로 처리함

Dispatch Queue의 동작 방식

  1. Sync (동기) : 처리가 끝날때까지 기다림
  2. Async (비동기) : 지시하고 다른 처리 함

따라서 총 4개의 조합이 나올 수 있음

  • Serial + Sync
  • Serial + Async
  • Concurrent + Sync
  • Concurrent + Async

시스템 실행 시 앱에서 기본적으로 다음 2개의 Queue를 만들어줌

Main Dispatch Queue

  • 앱의 메인 쓰레드에서 task를 실행하는, 전역적으로 사용 가능한 serial queue
  • 모든 UI이벤트는 Main Thread에서 처리해야함
  1. Dispatch.main은 Single Thread로 모든 Operation을 수행하는 Serial Queue.
  2. 만약 Sync를 하면 현재 수행중인 모든 작업을 block하고 sync 안에 있는 코드블럭으로부터 나오려고 함.
  3. 끝나지 않는 작업이 끝날 때까지 기다리므로 Deadlock 발생
  4. 따라서 main.sync 는 Thread safe 하지 않으므로 실행하지 말것!

main.sync 자세한 내용

Global Dispatch Queue

  • 편의상 사용할 수 있는 Concurrent Queue
  • 우선순위를 정할 수 있는 Qos 파라미터 제공
  • 수행되는 작업의 갯수는 시스템 상황에 따라 달라짐

Qos (Quality of Service)

  • 앱이 수행하는 작업에 적합한 QoS클래스를 정확하게 지정하면, 앱이 responsive하고 에너지 효율이 좋다는 것을 보장 할 수 있음

우선순위
1. user interactive - UI를 업데이트하거나 즉시 실행되어야 하는 코드들을 넣는다. Main 쓰레드에서 동작한다.
2. user initiated - user에 의해 실행되지만, 메인 쓰레드에서 동작할 필요가 없는 블럭을 실행한다. 즉각적인 결과를 필요로 할 때 사용한다.
3. utility - 다운로드와 같은 오래 걸리는 작업을 처리하기에 적합하다.
4. Background - 우선순위, 사용자의 눈에 보이지 않는 작업을 수행하기에 적합하다.


직렬 / 병렬 예시

1,2,3이라는 작업이 순서대로 Queue에 들어간다면

Concurrent 는 작업이 들어오는대로 전부 실행시킴
-> 2 3 1 순으로 끝날 수 있음 (먼저 끝나는대로)

Serial 은 먼저 들어온 작업이 끝날 때 까지 기다림
-> 1 2 3 으로 끝남

let serialQueue = DispatchQueue(label: "serial!!") // default = .serial
let concurrentQueue = DispatchQueue(label: "concurrent!!",attributes: .concurrent) // concurrent queue

print("start")

concurrentQueue.async {
    print("1")
}
concurrentQueue.async {
    print("2")
}
concurrentQueue.async {
    print("3")
}
concurrentQueue.async {
    print("4")
}
concurrentQueue.async {
    print("5")
}
concurrentQueue.async {
    print("6")
}
concurrentQueue.async {
    print("7")
}
concurrentQueue.async {
    print("8")
}
concurrentQueue.async {
    print("9")
}
concurrentQueue.async {
    print("10")
}


동기 / 비동기 예시

concurrentQueue.async {
    for i in 1 ..< 10 {
        print("sync2 \(i)")
    }
}

concurrentQueue.sync {
    for i in 1 ..< 10 {
        print("sync3 \(i)")
    }
}

print("main 1")

Concurrent 이기 때문에 sync2가 들어오고 sync3이 들어왔지만 둘 중 빨리 끝나는 작업부터 출력

sync2는 Async로 설정했기 때문에 작업을 실행시키고 다음 줄로 넘어감

sync3를 실행시키는 부분은 Sync이기 때문에 main1은 sync3가 모두 실행된 후 찍힘


결론

  • 순서가 중요한 경우 Sync, 아니면 Async
  • 무거운 작업(네트워킹 등) 은 background(global)에서, UI작업은 Main에서

참조
https://magi82.github.io/gcd-01/

https://zeddios.tistory.com/513
https://zeddios.tistory.com/510
https://zeddios.tistory.com/516
https://zeddios.tistory.com/520?category=682195

https://medium.com/flawless-app-stories/concurrency-visualized-part-1-sync-vs-async-c433ff7b3ebe
https://medium.com/flawless-app-stories/concurrency-visualized-part-2-serial-vs-concurrent-fd04e32c20a9
https://medium.com/flawless-app-stories/concurrency-visualized-part-3-pitfalls-and-conclusion-2b893e04b97d

https://www.notion.so/Concurrent-Programming-With-GCD-in-Swift3-c6554a3ccd654760bf06c97ac06f6b2a
https://www.notion.so/Modernizing-GCD-Usage-6ece2ab78f014237be94ce92138814d2

profile
iOS Developer

0개의 댓글