Notice
Recent Posts
Recent Comments
Link
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
반응형
Archives
Today
Total
관리 메뉴

슈프림 블로그

[iOS] 디스패치큐(GCD)의 종류와 특징, 그리고 주의사항 본문

iOS_Swift

[iOS] 디스패치큐(GCD)의 종류와 특징, 그리고 주의사항

_슈프림 2020. 12. 5. 22:03
728x90

DispatchQueue(GCD)의 종류

1. main queue : Serial

2. global queue : Concurrent / QoS 설정

3. private queue : 디폴트 Serial (Concurrent로 변경 가능) / QoS 추론


Main Queue

DispatchQueue.main

 

- 한개만 존재 => Main Thread에서 동작

- Serial (직렬)

- UI 처리를 담당

 

* 쓰레드 없이 날것의 코드를 실행하는 것은 Main Queue에서 sync로 실행하겠다는 것과 같은 의미이다.

* 하지만 DispatchQueue.main.sync는 코드로 사용할 수 없다. (에러)

 

실행방법

DispatchQueue.main.sync { ... } // 사용 불가! --ERROR--
DispatchQueue.main.async { ... } // 비동기적으로 main 쓰레드에 보냄
DispatchQueue.main.asyncAfter(.now()+2) {... } // 지금으로부터 2초 뒤에 비동기적으로 main 쓰레드로 보냄

Global Queue

DispatchQueue.global(qos:)

 

- QoS에 따른 6종류로 나뉨

- Concurrent(동시) : 여러개의 쓰레드로 분산 처리 함

 

서비스 품질 QoS (Quality of Service)

 - 중요한 순으로

    userInteractive, userInitiated, default, utility, background, unspecified

// 유저와 직접 인터렉티브 : UI관련 (즉시)
DispatchQueue.global(qos: .userInteractive)

// 반드시 필요, 비동기 처리 : 앱 내에서 첨부파일을 열기, 내부 데이터베이스 조회 등 (몇초)
DispatchQueue.global(qos: .userInitiated)	

// 일반적인 작업
DispatchQueue.global()	

// ProgressIndicator와 함께 길게 사용되는 작업 : 지속적인 데이터 feed, Networking (몇초~몇분)
DispatchQueue.global(qos: .utility)	

// 사용자가 직접적으로 인지하지 않는 부분 : 데이터베이스 유지 등 (속도보다는 에너지 효율성 중시)
DispatchQueue.global(qos: .background)

// 사용하지 않음 legacy API
DispatchQueue.global(qos: .unspecified)

작업을 쓰레드에 배치하는 일은 OS가 알아서 처리한다.

우선순위가 더 높은 큐의 작업을 우선적으로 더 많은 쓰레드에 배치하고 배터리를 집중적으로 소모하게 된다.

 

큐에도 우선순위를 메길 수 있지만, 작업을 대기열에 보내는 방식도 qos를 메길 수 있다.

background 품질의 global큐를 생성했다고 하더라도, 작업을 utility 품질로 보낼 수 있다.

이러한 경우에는 작업이 utility 품질로 더 높기 때문에, 내부적으로 큐 자체의 품질도 utility 수준으로 상승하게 된다.

let queue = DispatchQueue.global(qos: .background)
queue.async(qos: .utility) { ... }
// background queue도 작업의 품질에 영향을 받아 utility로 상승하게 됨

※주의사항※

다른 쓰레드로 분산처리 하기 위해 global큐를 사용하


Private Queue (커스텀 큐)

DispatchQueue(label:)

DispatchQueue(label: , attributes: ) 

 

- 디폴트 : Serial (Concurrent로 설정 가능)

- QoS 설정 가능 : 하지만 사실 서비스 품질을 굳이 설정해주지 않아도, OS가 알아서 QoS를 추론하게 된다.

- label을 설정해주면 된다.

 

사용 방법

let queue = DispatchQueue(label: "mySerialQueue")
let queue2 = DispatchQueue(label: "myConcurrentQueue", attributes: .concurrent)

기타 주의사항

※주의사항1※

UI관련 작업은 모두 Main Queue에서만 담당해야한다.

다른 Queue에서 작업하다가도, 화면에 표시해야 하는 작업은 반드시 MainQueue로 보내서 작업해야 함을 주의하자!!!

DispatchQueue.global().async {
    // (비동기 네트워크 작업) 이미지 다운로드
    ...
    
    DispatchQueue.main.async {
        // (UI관련) 다운로드한 이미지를 화면에 표시
    {
}

 

※주의사항2※

플레이그라운드에서는 mainQueue를 사용하지 않는다.

 

※주의사항3※

메인 큐에서 다른 큐로 보낼 때 sync를 사용하면 안된다.

다른 쓰레드에서 작업 하는 이유는 메인에서 동작하는 작업(UI관련 등)과 동시적으로 수행하여 속도를 향상시키기 위함인데,

sync를 사용하면 해당 작업이 끝날때까지 메인 쓰레드를 block 시키기 때문에 앱이 버벅이게 된다.

 

※주의사항4※

현재 큐에서 같은 큐로 sync를 사용하면 안된다.

실행되고 있던 쓰레드에서 현재 큐로 sync로 작업을 보내면 실행중이던 쓰레드는 block 상태가 된다.

다시 현재 큐에 들어온 작업을 쓰레드에 배치하는 과정에서 block 상태의 쓰레드에 배치된다면 교착상태가 발생한다.

 

※주의사항5※

작업을 보낸다는 것은 클로저를 보낸다는 것이므로 캡처 현상이 발생할 수 있다.

따라서 객체 내부에서 비동기 globalQueue를 사용할 경우, weak self 선언을 해주지 않으면 strong 참조를 하게 되어

작업 도중 객체가 사라지게 되어도 ARC가 남아있어 여전히 동작하게 된다. (strong capture현상)

따라서 weak 선언을 통해 객체가 사라질 때 작업도 자연스럽게 종료되도록 해야 한다.


위 포스팅은 인프런 강의 "iOS Concurrency(동시성) 프로그래밍, 동기 비동기 처리 그리고 GCD/Operation - 디스패치큐와 오퍼레이션큐의 이해 " 를 시청하고 작성한 글입니다.

www.inflearn.com/course/iOS-Concurrency-GCD-Operation/dashboard

 

반응형
Comments