GCD와 DispatchQueue는 같은 걸까?

오늘은 면접에서 GCD, DispatchQueue에 대한 질문이 들어왔지만 명확하게 답을 하지 못한 아쉬움에 나름 알고 있었다고 생각했던 GCD, DispatchQueue에 대한 정리를 자세하게 정리하고 나도 다시 공부하는 시간을 가져보려고 한다.

 

지금까지 그냥 내가 생각했던 내용은 GCD, DispatchQueue는 그냥 비슷한.. 동기, 비동기 처리를 지정해 사용할 수 있는 정도로 이해하고 넘어갔다.

 

지금까지는 개념만 이해하고 넘어가 구현 해보는 것에 집중했다면 이제 하나하나 정말 자세하게 알아보려고 한다. 현직자 분들과 얘기를 나눌수록 아 정말 내가 겉핥기식으로 공부하고 있었구나.. 하나를 가지고 생각하기 시작하면 끝도 없고 이 내용들을 알고 있어야 내가 구현하고자 하는 방식에 최적의 선택을 할 수 있다는 점을 뼈져리게 느끼고 있는 것 같다 🙂

 

GCD와 DispatchQueue는 같은 걸까?

먼저 이 부분을 짚고 넘어가자면 밀접하게 둘은 관련되어 있는 개념이지만 같은 것은 아니라는 것!

https://developer.apple.com/documentation/DISPATCH

 

Dispatch | Apple Developer Documentation

Execute code concurrently on multicore hardware by submitting work to dispatch queues managed by the system.

developer.apple.com

 

GCD는 멀티코어 시스템에서 동시성 실행을 제공하는 프로그래밍 언어 요소, 런타임 라이브러리라고 설명하고 있다.

 

즉 GCD는 작업단위 (클로저 , 코드블록 등)를 관리하고 시스템 리소스를 최적화하기 위해 관리하는 작업을 여러 스레드에서 비동기적으로 실행할 수 있는 Queue에 추가한다. 추가로 멀티스레딩을 쉽게 구현할 수 있도록 도와주고 성능을 최적화해 앱의 응답성을 개선한다.

 

https://developer.apple.com/documentation/dispatch/dispatchqueue/

 

DispatchQueue | Apple Developer Documentation

An object that manages the execution of tasks serially or concurrently on your app's main thread or on a background thread.

developer.apple.com

 

DispatchQueue는 GCD에서 작업을 관리하고 실행하는 Queue다 작업을 동기적(순차적) 혹은 비동기적(병렬적)로 실행하기 위해 사용된다. 이 둘은 Serial Queue, Concurrent Queue로 나눠서 생각할 수 있다.

 

Serial은 Queue의 작업을 동기적 즉 순차적으로 하나가 작업이 끝나면 실행하는 방식으로 동작하고 Concurrent는 작업이 비동기적 즉 동시에 병렬적으로 실행하도록 하지만 실행 순서는 보장하지 않는다.

 

위에서 정리한 내용을 생각해보면 GCD와 DispatchQueue는 같은것이 아니고 GCD의 동시성 프로그래밍을 지원하는 Swift API가 Dispatch Queue인 것이다!

 

이러한 DispatchQueue를 사용하게 되면 개발자는 작업을 정의해서 DispatchQueue에 넣어주기만 하면 멀티 스레드 방식을 통해 작업을 동기 혹은 비동기적으로 처리하게 될 수 있다는 점이다.

 

GCD Queue

여기까지 정리가 됐다면 다음에는 GCD에서 어떤 Queue를 제공하는지 알아보자.

 

GCD가 어떤 작업을 DispatchQueue를 사용해서 스레드에 작업을 효과적으로 실행할 수 있도록 한다는 것 까지는 이해가 됐다. 그럼 여기서 궁금한건 그럼 어떤 Queue에 넣어야 하는데? 라는 궁금증이 생긴다.

 

두가지로 나뉘는 것 같다 main Queue로 작업을 보내 처리할지 global Queue로 보내 처리할지.. 그렇담 두개의 차이를 알아보자.

 

Main Queue

메인큐는 말그래도 메인 스레드에서 작업을 수행할 수 있도록 하는 큐이다. 메인 큐는 메인스레드에서 동작하기 때문에 하나만 존재할 수 있어 Serial 특성을 가지고 있다. Serial의 특성은 순차적으로 작업을 실행하는 특징을 가지고 있다.

 

앱이 실행되면서 UI의 업데이트를 메인큐에서 담당해 처리하게 되기 때문에 UI업데이트와 관련된 모든 작업은 메인 큐에서 실행되도록 설정해야한다.

// GCD를 통해 메인 큐에서 UI 업데이트 수행
DispatchQueue.main.async {
    // UI 업데이트 코드
}

** 그렇다면 여기서 다시 생기는 의문.. 왜 UI업데이트 관련된 작업은 메인 쓰레드에서 실행되야하는걸까

 

그 이유는 메인 런루프가 뷰의 업데이트를 관리하는 View Dawing Cycle을 통해 뷰를 동시에 업데이트하는 설계를 통해 동작하고 있는데 백그라운드 스레드가 각자의 런루프로 UI를 업데이트하는 동작을 하면 뷰가 제멋대로 동작할 수 있기 때문이다. 또한 iOS가 그림 그리는 렌더링 프로세스가 있는데, 여러 스레드에서 각자의 뷰의 변경사항을 GPU로 보내면 GPU는 각각의 정보를 다 해석해야하니 느려지거나 비효율적이 될 수 있다.

 

Global Queue

글로벌 큐는 메인스레드가 아닌 다른 스레드에서 작업을 처리한다. 그리고 동시에 비동기 특성을 가지기 때문에 여러 스레드로 작업이 분산되어 병렬적으로 처리되게 된다.

// GCD를 통해 글로벌 큐에서 백그라운드 작업 수행
DispatchQueue.global(qos: .background).async {
    // 백그라운드 작업 코드
}

여기서 눈에 띄는건 qos인데 quality of service 라는 뜻으로 비동기적으로 작업이 분산되어 실행될 때 작업의 중요도를 설정해서 실행의 우선순위를 부여할 수 있는 기능이다!

우선순위가 더 높은 작업은 더 많은 스레드에 작업을 분산시키고 우선순위가 낮으면 적은 스레드에 분산하게 할 수 있다.

 

userInteractive > userInitiated > default > utility > background 순으로 중요도를 설정해줄 수 있다 🙂

// 글로벌 큐에서 백그라운드 작업을 수행하는 예제
DispatchQueue.global(qos: .background).async {
    // 여기서 시간이 오래 걸리는 작업을 수행합니다.
    // 예: 네트워크 호출, 파일 처리 등
    let data = fetchDataFromServer()

    // 메인 스레드에서 UI를 업데이트해야 하는 경우
    DispatchQueue.main.async {
        // UI 업데이트 코드
        myLabel.text = "Data received: \\(data)"
    }
}

오늘은 GCD와 dispatchQueue에 대해서 다시 한번 자세하게 알아보았다 🙂 다음엔 dispatchQueue를 사용한 실전 예제를 가지고 더 이해 할 수 있는 시간을 가져보려고 한다!

 

앞으로 뭐든 깊게 깊게 공부하도록 노력해야지!

 

오늘은 여기까지!