일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- Apple Developer Academy
- SwiftUI
- Project
- task.yield()
- Complication
- Firebase
- Swift
- fcm
- github
- ios
- createml
- backend
- coreml
- swift concurrency
- Sendbird
- cloud functions
- UIDatePicker
- Tuist
- WWDC22
- 코테
- tabman
- UITableView
- widgetkit
- app intents
- spring
- Coding Test
- Flutter
- watchkit
- UIStackView
- Delegate Pattern
- Today
- Total
azhy의 iOS 이야기
[iOS] GCD, Dispatch Queue 본문
2022년 5월 3일에 작성됨
우리는 보통 GCD, Dispatch Queue를 구분하지 않고 부릅니다.
요번에 정리하며 알게 됐는데 공식문서를 보면 GCD는 동시성 실행을 제공하는 프로그래밍 언어 요소, 런타임 라이브러리 등이라고 합니다.
그래서 따지고 보면 GCD랑 Dispatch Queue는 같지는 않지만 GCD의 개념으로 동시성 프로그래밍을 지원하는 친구가 Dispatch Queue라서 같은 의미로 봐도 무방할 것 같습니다.
다른 언어와 달리 iOS 는 Dispatch Queue에 작업을 넣으면 운영체제가 알아서 스레드에 할당해 주는 특징이 있습니다.
Serial, Concurrent
Dispatch Queue에는 2가지 종류가 있는데 Serial과 Concurrent가 있습니다.
Serial
등록된 작업들을 한 번에 하나씩 처리
Concurrent
등록된 작업들을 여러작업으로 (여러 스레드) 처리
기본은 Serial 이며 Concurrent로 작업하려면 attributes를 따로 세팅해야 합니다.
let dispatchQueue = DispatchQueue(label: "concurrent", attributes: .concurrent)
추가로 Private Queue (커스텀 큐)로도 만들 수 있는데 다음과 같이 사용하면 됩니다.
let queue = DispatchQueue(label: "mySerialQueue")
let queue2 = DispatchQueue(label: "myConcurrentQueue", attributes: .concurrent)
Sync, Async
그리고 Sync, Async를 지정할 수 있는데 Sync는 동기, 큐에 추가된 작업이 완료될 때까지 기다리는 것이고, Async는 비동기, 큐에 작업을 등록하면 완료 여부와는 상관없이 계속 작업을 진행하는 것입니다.
Main, Global
Dispatch Queue를 사용할 때 기본적으로 2가지의 queue를 제공하는데 바로 main과 global입니다.
Main Queue
Main Queue는 메인 쓰레드에서 작업을 실행하며 Serial의 특성을 가집니다. 그리고 UI의 업데이트에 관련된 모든 작업은 Main Queue에서 작동되어야 합니다.
sync는 작업이 끝날 때까지 기다리기 때문에 UI 업데이트를 담당하는 main queue는 main.sync를 하면 안 됩니다.
(자세한 내용은 Zedd님이 잘 정리해 놓으셔서iOS ) 왜 main.sync를 하면 안 될까 를 보면 좋을 것 같습니다)
DispatchQueue.main().async{}
Global Queue
Global Queue는 Concurrent의 특성을 가져서 작업이 분산되어 처리됩니다.
DispatchQueue.global().async{}
DispatchQueue.global().sync{}
QOS
Quality of Service, QOS는 Global Dispatch Queue에 추가할 수 있는데 작업의 중요도를 설정해서 우선순위를 정할 수 있습니다.
우선순위가 높은 작업은 우선순위가 낮은 작업보다 더 빨리 수행되기 때문에 앱이 수행하는 작업에 적합한 QoS클래스를 정확하게 지정하면, 앱의 성능이 더 좋아진다고 합니다.
(우선순위가 높은 순으로 정리했으며 공식문서 참고했습니다)
- userInteractive : 사용자와 상호작용하는 작업, 애니메이션 처리, UI 업데이트 등의 경우이며 사용자의 요청에 바로 작업이 수행되어야 해서 가장 높은 우선순위를 가집니다.
DispatchQueue.global(qos: .userInteractive) (즉시) - userInitiated : 사용자가 요청을 했을 때 결과를 즉각적으로 받아야 하거나, 사용자가 앱을 사용하는 것을 막는 작업에 할당합니다. 예를 들어, 이메일의 내용을 로드하거나 앱 내에서 첨부파일을 열기, 내부 데이터베이스 조회 등에 사용할 수 있습니다.
DispatchQueue.global(qos: .userInitiated) (몇 초) - default : 기본값이며, 일반적인 작업인 경우 사용합니다.
DispatchQueue.global() - utility : 사용자가 앱을 계속 사용하는 것을 방해하지 않는 작업에 할당합니다. 예를 들어 사용자가 진행 상황을 적극적으로 따르지 않는 작업, 사용자와 상호작용하지 않는 작업에 사용할 수 있습니다. ex : progress bar, 지속적인 데이터 feed, Networking
DispatchQueue.global(qos: .utility) (몇 초 ~ 몇 분) - background : 백그라운드 작업은 모든 작업 중에서 우선순위가 낮습니다. 백그라운드에서 작동하는 작업에 사용할 수 있습니다.
DispatchQueue.global(qos: .background)
Serial + Sync
Sync로 설정했으니 코드가 실행될 때 Serial Dispatch Queue에 작업을 하나 등록하면, 해당 작업이 완료될 때까지 기다립니다.
(main.sync 는 사용을 못하니 주의, 등록순서, 출력순서 일치 o)
Concurrent + Sync
Sync로 설정했으니 큐에 등록되는 작업들은 여러 스레드에 분산되어 처리되는데, 앞에 작업이 완료될 때까지 대기합니다.
(등록순서, 출력순서 일치 o)
Serial + Async
Async로 설정했으니 작업의 등록은 앞의 작업 완료여부와 상관없이 계속 진행하고, 작업의 수행은 순차적으로 진행합니다.
(등록순서, 출력순서 일치 o)
Concurrent + Async
Async로 설정했으니 작업을 완료 여부와 상관없이 계속 등록하고, 등록된 작업들은 스레드에 분산되어서 동시에 실행됩니다.
(등록순서, 출력순서 일치 x)
추가로 주의해야 하는 상황
메인 큐에서 다른 큐로 보낼 때 sync를 사용하면 안 된다.
메인 큐에서 다른 큐로 보내서 작업하는 이유는 메인에서 동작하는 작업과 동시적으로 수행하여 속도를 향상하기 위함인데, sync를 사용하면 해당 작업이 끝날 때까지 메인 쓰레드를 block 시키기 때문에 앱이 버벅거리게 됩니다.
현재 큐에서 같은 큐로 sync를 사용하면 안 된다.
실행되고 있던 쓰레드에서 현재 큐로 sync로 작업을 보내면 실행 중이던 쓰레드는 block 상태가 됩니다.
'iOS' 카테고리의 다른 글
[iOS] Font 추가하기 (2) | 2024.11.11 |
---|---|
[iOS] github에 API Key 숨기기 (0) | 2024.11.11 |
[iOS] 앱 기본 언어 한국어로 변경하는 법 (1) | 2024.11.11 |
[iOS] 다사다난했던 첫 앱 출시 후기 (5) | 2024.11.11 |
[iOS] swift 알고리즘, 코딩테스트에 필요한 tip 정리 (3) | 2024.11.08 |