[Swift] Dispatch Queue 종류

2025. 2. 21. 02:24·iOS/Swift
728x90
반응형

안녕하세요, iOS 개발하는 루피입니다.

 

오늘은 Dispatch Queue의 종류에 대해 살펴보는 시간은 가져보겠습니다.

 

바로 시작합니다.


시작하기에 앞서..

Queue의 종류에 대해 헷갈리는 분들이 많을 거 같아 본격적으로 글을 작성하기 전에 간단하게 정리하고 가겠습니다!!

 

Dispatch Queue라는 큰 범위가 있고 그 안에 Serial Queue, Concurrent Queue, Private Queue 가 있다고 생각하시면 됩니다. ( Private Queue는 쉽게 말해 커스텀 Queue라고 생각하시면 됩니다. 우리가 Cuncurrent 특성을 가질지 아니면 Serial 특성을 가질지 설정할 수 있고 Default로는 Serial 특성을 가지고 있습니다 )

 

그리고 Serial Queue 안에 그 특성을 가지는 Main Queue와 Concurrent Queue 안에 Global Queue가 있습니다.

이때 Main과 Global은 개발자가 만든 Queue 가 아니라 시스템적으로 자동으로 만들어주는 Queue라는 차이를 가지고 있습니다.


Main Queue

let mainQueue = DispatchQueue.main

현재 프로세스의 메인 스레드와 연결된 Dispatch Queue로, Serial Queue의 특성을 Default로 가지고 있으며, UI 작업과 같은 메인 스레드 전용 작업을 관리합니다.

 

그렇기 때문에 Main Queue는 Global Queue와 마찬가지로 suspend(), resume() 같은 메서드를 사용해도 아무런 효과가 없습니다. 이는 Main Queue는 시스템이 관리하며, 앱의 라이프사이클과 UI 응답성에 직접적으로 연결되어 있기 때문인데요.!! 

만약 사용자가 원하는 대로 Main Queue를 정지(suspend())하거나 재개(resume())할 수 있다면, UI가 멈추거나 사용자 입력에 반응하지 않는 등 심각한 문제가 발생할 수 있습니다.

 

예를 들어, 버튼 클릭 이벤트가 처리되지 않거나 화면 전환이 중단되면 사용자 경험이 크게 저하되고, iOS의 Watchdog 메커니즘이 0x8badf00d 예외를 발생시켜 앱을 강제로 종료할 위험도 있습니다. (밑에서 다뤄 보겠습니다!!)

 

GCD는 이런 문제를 방지하기 위해 시스템이 Main Queue를 완전히 제어하며, 개발자의 임의적 중단을 허용하지 않습니다.

Main Queue에서 작업을 제어해야 할 때는 DispatchWorkItem.cancel()이나 DispatchGroup을 활용해 특정 작업만 세밀히 관리하는 방식이 적합합니다.
예를 들어, 긴 작업(네트워크 호출, 파일 처리 등)은 반드시 백그라운드 큐에서 실행한 후, 결과를 Main Queue로 전달해 UI를 업데이트하는 방식으로 메인 스레드 응답성을 유지해야 합니다.

 

시스템은 자동으로 이 Queue를 생성하고 메인 스레드와 연결합니다. 앱은 Main Queue에 제출된 작업을 실행하기 위해 3가지 접근 방식을 사용할 수 있습니다.

  1. dispatchMain()를 호출하는 방식
  2. iOS에서는 UIApplicationMain, macOS에서는 NSApplicationMain을 호출하는 방식
  3. 메인 스레드에서 CFRunLoop를 사용하는 방식

3가지 방식 중 하나만 선택해도 됩니다!

 

근데 하나 궁금한 게 있지 않으신가요? 아니 우리는 따로 코드를 작성하지 않았는데 메인 스레드를 사용하고 있는데요??? 

네 맞습니다. 하지만 우리는 이미 한 가지 방식을 사용하고 있습니다.

 

바로..!!

2번 방식을 우리는 사용하고 있기 때문입니다!!

 

우리 모두 위에 두 코드가 익숙하지 않으신가요?? 맞습니다.

주로 UIkit, SwiftUI를 이용해 개발을 시작하기 전에 기본적으로 제공되는 템플릿 안에 있는 코드들입니다.

 

여기서 @main이 바로 UIApplicationMain을 호출하는 코드입니다. 그리고 호출된 UIApplicationMain이 메인 스레드와 Main Queue를 설정하는 것입니다.

 

1번과 3번에 관해서도 간략히 말하자면, 주로 low-level 프로젝트나 앱에서 주로 사용되는 방식이라고 알고 계시면 될 거 같습니다!

중요 (공식 문서가 인정한 중요 포인트 )

메인 스레드는 너무 오랫동안 응답하지 않으면, mach_msg_trap에서 0x8badf00d 예외가 발생할 수 있다고 하는데요??? iOS에서 이 예외는 감시 메커니즘이 "앱이 특정 사용자 인터페이스 이벤트에 제시간에 응답하지 못했다"라고 감지할 때, 발생할 수 있다고 합니다.

 

iOS의 감시 메커니즘은 사용자 인터페이스가 항상 반응하도록 유지하기 위해 존재하며, 만약 앱에 네트워크 호출과 같은 긴 작업이 있다면, Global Queue 나 다른 Background DispatchQueue(Private Queue)에서 실행하거나, 가능하다면 비동기 버전의 호출을 사용하는 것이 좋습니다.

❌ MainQueue.sync { } ❌

MainQueue.sync를 사용할 경우 데드락이 발생해 충돌이 발생하게 됩니다. 

Button("MainQueue") {
       print("A",Thread.current)
       MainQueue.sync {
           print("B",Thread.current)
       }
       print("K",Thread.current)
}

1. Button 이 클릭되는 순간 MainQueue에 Action block(ㄱ이라고 칭하겠습니다.)이 할당됩니다.

2. A가 출력이 된 이후 MainQueue.sync { }(ㄴ이라고 칭하겠습니다.)를 마주하게 됩니다.

3. MainQueue에 sync 작업 ㄴ을 할당하게 됩니다. (이때 MainQueue 제일 뒤에 ㄴ이 추가되는 겁니다)

 

여기서 데드락이 발생하게 됩니다.

MainQueue는 SerialQueue의 특성처럼 한 번에 하나의 작업을 처리하는 특성을 가지고 있습니다.

이때 ㄱ의 작업을 진행 중에 ㄴ 작업을 처리해야 한다는 문제점에 봉착하게 됩니다.

 

결국 ㄱ는 ㄴ이 실행되어야만 종료가 될 수 있으며, ㄴ은 실행 중인 작업인 ㄱ이 해결되어야만 실행될 수 있는 상태입니다.

그리고 이것을 우리는 데드락이라고 말합니다.

그러면 Serial.sync는 왜 되는 건데.. ❓❓

결론부터 말씀드리자면 Queue가 동일하지 않기 때문입니다.

Button("SerialQueue") {
       print("A",Thread.current)
       SerialQueue.sync {
           print("B",Thread.current)
       }
       print("K",Thread.current)
}

1. Button 이 클릭되는 순간 MainQueue에 Action block(ㄱ이라고 칭하겠습니다.)이 할당됩니다.

2. A가 출력이 된 이후 SerialQueue.sync { }(ㄴ이라고 칭하겠습니다.)를 마주하게 됩니다.

3. SerialQueue에 sync 작업 ㄴ을 할당하게 됩니다. (이때 SerialQueue 제일 뒤에 ㄴ이 추가되는 겁니다)

 

위에서는 MainQueue 1개만 있던 것과 다르게 Queue가 2개 있는 상황입니다.

바로 Main Queue와 Serial Queue 2개가 있기 때문이죠. 

 

그렇다면 Serial 특성이 문제가 되지 않습니다. 왜냐하면 Queue 2개는 독립된 것이기 때문입니다.

 

즉, "Main Queue의 ㄱ이 아직 안 끝났는데 Serial Queue에서 ㄴ을 처리하면 안 돼!!"라는 상황이 아니라, 

"알겠어, 그럼 Main Queue 너는 잠깐 기다려. 내가 Serial Queue에서 ㄴ을 먼저 처리할게!" 같은 상황이 되는 겁니다.


여기서 헷갈릴 수 있어요. 


"아니, 그럼 이게 Concurrent 아냐?"라고 생각할 수 있는데, 아니에요! 


Main Queue와 Serial Queue는 서로 독립적인 큐이기 때문에 각각 따로 처리할 수 있는 거예요. 
반면, Concurrent라는 개념은 하나의 큐 안에서 여러 작업을 동시에 처리 할 수 있다는 뜻입니다. 
이렇게 이해하시면 훨씬 명확할 거예요!


Global Queue

 let globalQueue = DispatchQueue.global(qos: .default)

GCD를 통해 제공되는 시스템 수준의 동시 큐로 시스템이 미리 생성해 제공하는 Concurrent 작업을 처리할 수 있는 큐입니다. 따라서 개발자는 직접 생성할 필요 없이, DispatchQueue.global()을 통해 바로 접근할 수 있습니다.

 

Global Queue는 메인 스레드와는 별개로, 항상 백그라운드 스레드에서 작업을 동시에 실행할 수 있도록 설계되었습니다.

그렇기에 UI 작업보다는 주로 네트워크 요청, 데이터 처리, 파일 I/O 등 시간이 오래 걸리는 작업을 처리하는 데 적합합니다.

 

Qos 등급을 지정해 작업의 우선순위를 조정할 수 있습니다.

  • userInteractive: UI와 직접 관련된 작업. 가장 높은 우선순위
  • userInitiated: 사용자가 요청한 작업. 빠른 응답 필요
  • default: 기본 우선순위. 명시적 QoS가 없는 작업
  • utility: 장기 실행 작업. 중간 우선순위
  • background: 사용자에게 보이지 않는 작업. 가장 낮은 우선순위
  • unspecified: QoS가 명시되지 않음. 시스템이 우선순위를 동적으로 결정

Global Queue는 시스템이 관리하므로 Main Queue와 똑같이 suspend(), resume(), dispatch_set_context() 같은 메서드는 효과가 없습니다. 왜냐면 시스템이 직적 다루는 Queue이기 때문입니다! 다들 아시죠?


오늘도 화이팅입니다!

728x90
반응형

'iOS > Swift' 카테고리의 다른 글

[Swift] Dispatch Work Item  (0) 2025.02.24
[Swift] Dispatch Group  (0) 2025.02.23
[Swift] Concurrent + Sync 에 대한 궁금증  (0) 2025.02.19
[Swift] DispatchQueue  (0) 2025.02.19
[Swift] GCD를 공부해봅시다.  (0) 2025.02.18
'iOS/Swift' 카테고리의 다른 글
  • [Swift] Dispatch Work Item
  • [Swift] Dispatch Group
  • [Swift] Concurrent + Sync 에 대한 궁금증
  • [Swift] DispatchQueue
kimsangjunzzang
kimsangjunzzang
루피 님의 블로그 입니다.
  • kimsangjunzzang
    루피 님의 블로그
    kimsangjunzzang
  • 전체
    오늘
    어제
    • 분류 전체보기 (91) N
      • iOS (55)
        • Swift (26)
        • UIKit (9)
        • SwiftUI (8)
        • RxSwift (12)
      • FE (8)
        • 모던 자바스크립트 (3)
        • HTML (5)
      • Operating System (1)
      • 트러블 슈팅 (4) N
      • 바로 안 나오면 모르는거다 (4)
      • Algorithm (16)
      • 회고록 (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    JavaScript
    FP
    AppleDeveloperAcademy
    회고록
    C++
    web
    boj
    swift
    오블완
    HTML
    디자인 패턴
    gcd
    state
    알고리즘
    SwiftUI
    arc
    Delegate
    주니어 개발자
    life cycle
    CS
    DispatchQueue
    rxswift
    Algorithm
    티스토리챌린지
    ViewController
    uikit
    ios
    백준
    면접
    closure
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
kimsangjunzzang
[Swift] Dispatch Queue 종류
상단으로

티스토리툴바