[iOS] 멀티스레드와 Queue
멀티 스레드란?
하나의 프로세스 내에서 여러 스레드가 동시에 작업을 수행하는 것으로 하나의 프로세스 내에서 여러개의 스레드가 존재하고 각 스레드들이 프로세스의 자원을 공유하되 실행은 독립적으로 이루어지는 구조이다.
NSOperationQueue
Objective-C 기반의 고수준 API로 NSOpertion 객체의 우선운위 및 준비 상태에 따라 대기열에 있는 객체를 실행한다. GCD에서는 할 수 없는 기능(재개, 취소, 중지)을 제공하지만 구현이 복잡하고 무겁우며 야간의 오버헤드를 발생시킨다. 또한 모든 작업이 끝나지 않은 상태에서 Operation queue를 중지시키면 메모리 릭이 발생할 수 있다. NSOpertation을 NSOperationQueue에 추가하여 실행시키는 동작 방식이며 이때 NSOperationQueue는 ConcurrentQueue로 동작한다.
GCD와는 다르게 KVO(Key-Value Observing) 사용이 가능하다.
A객체에서 B객체의 프로퍼티가 변화됨을 감지할 수 있는 패턴이다. Notification이 주로 Controller와 다른 객체 사이의 관계를 다룬다면 KVO는 객체와 객체 사이의 관계를 다루는데 적합하다.
두 객체 사이의 정보를 맞춰주는 것이 쉽고 New / Old value를 쉽게 얻을 수 있으며 KeyPath로 옵저빙하기 떄문에 nested objects도 옵저빙이 가능하다는 장점이 있다.
하지만 NSObject를 상속받은 객체에서만 사용이 가능하고 dealloc될 때 옵저버를 지워줘야 한다는 단점도 있다.
dealloc?
Objective-C에서 사용되는 개념으로 개게의 메모리 할당이 해제될 때 호출되는 메소드이다. Swift 자체에는 dealloc 메소드가 존재하지 않는 대신에 클래스 인스턴스의 메모리 할당이 해제되기 직전에 호출되는 deinit 키워드가 있다.
GCD(Grand Central Dispatch) Queue
동시성 모델을 매우 간단하게 사용할 수 있는 low-level C 기반 API이다. 앱의 메인 스레드 또는 백그라운드 스레드에서 작업의 실행을 직렬 또는 동시에 관리하는 객체이다. 한마디로 Apple의 다중 스레드 프로그래밍 기술이다. 메인 스레드가 하던 일들을 Queue에 보내고 적절히 생성하여 분배해주는 기능을 한다.
DQ에 작업을 추가 -> 작업에 맞는 스레드를 자동으로 생성하여 분배 -> 작업이 종료되면 스레드 제거
dispatchQueue
작업을 순차적으로 또는 동시에 실행하는 FIFO Queue이며 DQ에 제출된 작업은 시스템에서 관리하는 스레드 풀에서 실행된다.
GCD API에서 스레드를 관리하는 클래스인 셈이다. 동시성에 따른 종류로는 직렬큐인 SerialQueue와 병렬큐인 ConcurrentQueue가 있으며 사용목적에 따른 종류로는 MainQueue, GlobalQueue, CustomQueue가 있다.
SerialQueue
이전 작업이 끝나면 다음 작업을 순차적으로 실행하는 직렬 형태의 큐이다. 분산처리시킨 작업을 다른 한개의 쓰레드에서 처리하므로 한번에 하나의 작업만 수행한다. 작업의 시작과 종료에 대한 순서 예측이 가능하므로 순서가 중요한 작업들을 처리할 때 사용하면 적절하다.
ConcurrentQueue
이전 작업이 끝날때까지 기다리지 않고 병렬 형태로 동시에 작업을 실행하는 큐이다. 분산처리시킨 작업을 다른 여러개의 쓰레드에서 처리하므로 동시에 여러 작업을 수행한다. 작업의 시작과 종료에 대한 순서 예측이 불가능하므로 순서가 중요하지 않고 빠르게 처리하는 작업에 적절하다.
MainQueue
메인 스레드에서 실행되는 Queue로 UI 작업을 하는 코드가 이 메인 큐에서 실행되며 SerialQueue의 특성을 가진 큐이다. 오직 한개만 존재한다. 참고로 MainQueue에 동기 작업을 추가할 시에 Deadlock이 발생할 수 있으므로 절대 Sync 작업을 추가할 수 없다!
GlobalQueue
메인 스레드가 아닌 다른 스레드에서 실행되는 DQ로 QoS 설정이 가능하며 ConcurrentQueue의 특성을 가진 큐이다.
Custom(Private)Queue
기본적으로 SerialQueue 이지만 ConcurrentQueue로 서ㅗㄹ정이 가능하고 Qos도 설정이 가능하다. 매개변수로는 label, qos, attributes가 있다.
QoS(Quality of Service)
Cooncurrent 하게 작업을 처리하면서 작업의 우선순위를 지정하기 위해 사용된다. 우선순위에 따라
userInteractive -> userInitiated -> default -> utility -> background -> unspecified 가 있다.
- userInteractive: UI 업데이트 같은 사용자와 직접 상호작용하는 작업 (즉각적으로 실행)
- userInitiated: 저장된 파일을 열거나, 클릭같은 비교적 빠른 결과가 필요한 작업 (몇 초 이하 / 거의 즉시)
- default: 일반적인 작업
- utility: 데이터 다운로드 같은 progressBar와 함께 길게 실행되는 작업 (몇 초 ~ 몇 분)
- background: 동기화나 백업 같은 유저가 직접 인지하지 않는 시간이 덜 중요한 작업 (몇 분 ~ 몇 시간)
- unspecified: QoS 정보가 없음을 나타내고 시스템에게 QoS를 추론하라는 신호를 준다.
Sync & Async & Serial & Concurrent
SerialQueue.sync
메인 스레드의 작업 흐름이 queue에 넘긴 태스크가 끝날때까지 멈춰있고(sync)
넘겨진 task는 queue에 먼저 담겨있던 작업들과 같은 스레드에 보내지기 때문에 해당 작업들이 모두 끝나야 실행 (Serial Queue)
ConcurrentQueue.sync
메인 스레드의 작업 흐름이 queue에 넘긴 태스크가 끝날때까지 멈춰있고(sync)
넘겨진 task는 queue에 먼저 담겨있던 작업들과 다른 스레드에 보내질 수 있기 때문에 해당 작업들이 모두 끝나지 않아도 실행 (Concurrent Queue)
SerialQueue.async
메인 스레드의 작업 흐름이 태스크를 queue에 넘기자마자 반환되고 (async)
넘겨진 task는 queue에 먼저 담겨있던 작업들과 같은 스레드에 보내지기 때문에 해당 작업들이 모두 끝나야 실행 (Serial Queue)
ConcurrentQueue.async
메인 스레드의 작업 흐름이 태스크를 queue에 넘기자마자 반환되고 (async)
넘겨진 task는 queue에 먼저 담겨있던 작업들과 다른 스레드에 보내질 수 있기 때문에 해당 작업들이 모두 끝나지 않아도 실행 (Concurrent Queue)
댓글남기기