안녕하세요 :) 소들입니다..
오늘은 iOS의 이 쓰레드란 놈에 대해 마무리를 지어볼까 해요..
아마 이번에 GCD좀 다루면 대강 끝나지 않을까 싶네요 :)
먼저 iOS의
Main Thread / Global Thread 에 대해서 이해를 하고,
그 뒤에 NSOperation과 GCD를 다뤄볼까 합니다 :)
Sync / Async, Serial / Concurrent에 대한 기본지식이 있다는 전제 하에 진행하니
혹시 모른다면 이 포스팅을 꼭 보고 와주세염~~~~~~
모든 포스팅은 편의 말투로 합니다~!!
1. Main Thread / Global Thread
음..... 개발을 하다보면
정말 많이보게 되는 그런 녀석들임 이것들에 대해 먼저 짚고 넘어가겠음 👀
1-1. Main Thread
iOS에서 Main Thread는 오직 한 개만 존재함!
우리가 평소에 아무렇지 않게 작성하는 코드들이 바로 이 Main Thread에서 동작하는 것인데,
이 작성된 코드가 Cocoa에서 실행될 때, Main Thread에서 호출하기 때문임!!
또 Main Thread의 중요한 것 중 하나는,
이 Main Thread는 Interface Thread라고도 불리는데,
그 이유는 UI와 관련된 작업은 모두 이 Main Thread에 붙기 때문에,
UI와 관련된 작업은 반드시 Main Thread에서 작성해야 함!!
만약 Main Thread가 아닌 곳에서 UI 관련 작업을 실행하려고 하면
이런 식으로 RunTime 중에 보라색 오류가 남 👀
근데 이 Main Thread에서 시간이 걸리는 작업을 실행하게 되면,
그동안 어플 화면이 정지된 것처럼 멈춰있음
왜냐면 좀이따 나올거지만, Main Thread는 Main Queue에서 실행되는데,
이 Main Queue가 Serial Queue라서, 한번에 한 개의 Task밖에 실행하지 못함
따라서, UI를 실행하는 데에 영향을 줄만한 코드들은 Main Thread에서 실행하면 안 되고,
다음에 나오는 Global Thread로 실행시켜 줘야 함 :)
1-2. Global Thread (Background Thread)
편의상 Background Thread라고 부르겠음!
iOS에서의 Framework들은 모두 Background에서 구동이 됨
몸체는 Background에 있지만, 가끔 필요할 때 Main Thread에게 손(Delegate)을 뻗는 구조임!
무슨 말이냐면
예를 들어, 우리가 어플에서 음악을 재생하려고 하면 음악 재생에 필요한 Framework를 쓸 것이잖음?
이때 음악 재생에 필요한 Framework 작업들은 모두 Background에서 실행되고,
필요에 따라 음악 재생 성공했다! 같은 것을 알려줄 때 Delegate, Completion Handler 등을 통해
Main Thread에게 알려 통제할 수 있는 것임
만약 iOS Framework 작업이 모두 Main Thread에서 작동한다면,
앱의 화면은 계~~~~~속 멈춰있을 것임!!
근데, 자동으로 Background에서 실행되는 것 외에도
코드 실행이 오래 걸리는 작업은 직접 Background Thread로 실행시켜주어야 함
자, 이제 Thread 종류에 대해 알았으니
Queue 종류에 대해 알아보자 :)
2. NSOperation / GCD
앞서, Thread의 종류와 사용 이유?에 대해 알아봤다면,
iOS에선 Multi Threading 할 때 어떤 방식으로 하는지 알아보겠음!
먼저 애플은 쉽고편한 Multi Threading을 위하여 2가지 API를 제공하는데
NSOperation
GCD
이 외에 NSThread도 있지만 이 두가지에 대해서만 다루겠음!!
(그중에서 오늘 내용은 GCD이기에 NSOperation은 간단히 ㅎㅎ)
2-1. NSOperation
Objective-C언어 기반의 고수준 API
NSOperation은 내부적으로는 C로 구현된 GCD를 고수준 언어로 Wrapping 한 것이고,
따라서 GCD보다 다소 무겁고 약간의 오버헤드를 발생시킴!!
하지만 고수준 API인 만큼,
GCD엔 없는 기능들을 사용할 수 있다는 장점을 가지고 있음
대충 어떤 기능들이냐면,
작업 취소, KVO(나중에 포스팅 할 예정), 작업 재사용 등등
GCD에서 하려면 귀찮은 작업들을 제공해서
사용하기 편하다는 장점이 있다 함 :)
NSOperation 동작 방식은 작업 단위인
NSOperation을 NSOperationQueue에 추가하여 실행시키는 방법인데,
이때 NSOperation Queue는 Concurrent Queue로 동작함
근데 실제 많이 사용하는 건 NSOperation 보다 GCD이니,
NSOperation 사용법은 나중에 따로 포스팅 하겠음 :)
2-2. GCD (Grand Central Dispatch)
C언어 기반의 저수준 API
대망의 GCD!!! 드디어 나왔다💩
GCD는 C언어 기반이기 때문에 NSOperation보다 가볍고 성능면에서 좋다함!
또한 Block(Closure)로 구현되어 있어 코드 가독성면에서 좋고 간단하게 사용가능 하지만,
작업 취소, KVO, 재사용 등등은 직접 만들어줘야 한다는 귀찮음이 있음😱
쨌든 GCD의 정의는 이렇고,
이 GCD는 Dispatch Queue라는 것을 사용해서 Multi Threading을 지원함!
먼저, Dispatch Queue에 대해 알아보자 :)
DIspatch Queue
NSOperation에서 NSOperationQueue를 이용해 작업을 관리 했다면,
GCD에선 이 Dispatch Queue라는 것을 이용해 작업을 관리함!
DIspatch Queue는 2가지 Type이 존재하는데,
① Serial Queue
Task(작업)들을 순차적으로 처리하며,
한 번에 한 개의 Task 밖에 처리하지 못함
② Concurrent Queue
동시에 여러 개의 Task들을 처리함
Serial / Concurrent에 대한 것은 이전 포스팅에서 다뤘으니 가볍게 넘어갈게여 :)
.
.
또한 Dispatch Queue는 App이 실행함과 동시에 구조적으로 2가지 Queue가 자동생성되는데,
가장 처음에 언급했던 Main / Global Thread와 관련된내용임!!!
① Main Queue (Serial Queue)
Main Thread에서 사용되는 Queue로 Serial Queue이고,
당연히 UI 관련 작업은 이곳에서 처리되어야 함!
Main Queue에 작업을 추가하고 싶다면, 다음과 같이 해주면 됨
DispatchQueue.main.async {
//원하는 작업
}
|
DispatchQueue 중 main queue에 async로 추가하겠다! 이런 식으로 등록함
참고로, Main Queue에는 절대 절대 Sync Task를 추가할 수 없음
이유는 찾아보니까 Main Thread가 Thread-Safe하지 않아서라는데,
난 아직 이해가 안가서 ;ㅁ; 이해가 가면 나중에 추가 하겠음
근데 쨌든, main.sync는 절대절대 사용하면 안됨!!!!!!!!!!!!
컴파일 시에 문제 없는데염?? 하겠지만, 런타임 에러로 떨어지니까 Async만 사용하셈
② Global Queue (Concurrent Queue)
Global Queue는 편의상 사용할 수 있게 만들어 놓은 Concurrent Queue이고,
정의에서 보다 싶이 Qos라는 것을 지원함
이 Qos가 뭐냐면, Priority(우선 순위)인데, 이 우선 순위를 우리가 직접 명시해줄 수 있음
userInteractive | 중요도가 높고 즉각적인 반응이 요구되는 작업(UI업데이트, 이벤트핸들링 등)일 때 사용 Main Thread에서 실행되는 Qos |
즉각적으로 실행 |
userInitiated | userInteractive까진 아니더라도 유저가 빠른 결과를 기대할 때 사용 저장된 파일을 열거나 할 때 사용 |
몇 초 이하나 거의 즉각적 |
default | 작업을 분리하지 않을 때 사용되는 Qos로 기본값임 | |
utility | 즉각적인 결과가 필요하지 않을 때 프로그레스 바가 등장하는 작업에 어울림 (네트워크, 다운로드, 계산, 데이터를 가져오기 등을 처리 등) |
몇 초 ~ 몇 분 |
background | 급히 필요하지 않은 작업일 때 사용자에겐 보이지 않는 처리 (ex: 백업) background로 줄 경우 iPhone 저전력 모드에선 실행되지 않는다 |
몇 분 ~ 몇 시간 |
unspecified | Qos 정보가 없음을 나타냄 시스템에게 Qos를 추론하라는 신호를 줌 |
이 Qos를 잘 활용하면 에너지 효율성이 좋아진다고 함 :)
Global Queue에 작업을 추가하고 싶다면, 다음과 같이 해주면 됨
DispatchQueue.global().sync {
//원하는 작업
}
DispatchQueue.global().async {
//원하는 작업
}
|
sync, async를 지정해서 위와 같이 호출해주면 되고,
Qos를 딱히 지정하지 않으면 .Default로 지정됨!!!!
만약, Qos를 지정하고 싶다면
DispatchQueue.global(qos: .userInteractive).sync {
//원하는 작업
}
|
이런 식으로 직접 지정해주면 됨:)
이렇게 자동 생성되는 Queue 외에도
내가 직접 Queue를 만들고 싶다!!!!!111 하면 만들 수 있음
+ Private Queue (사용자 지정 큐)
다음과 같이 만들면 됨 👀
let myQueue = DispatchQueue.init(label: "myQueue", qos: .background attributes: .concurrent)
myQueue.async {
//원하는 작업
}
|
쨘-
.
.
.
흠.........
이외에도 Dispatch Semaphore나 Lock 등등에 대해
더 다루고 싶은데 그건 따로 포스팅 하겠습니다 🌝
피드백, 잘못된 내용 환영
'iOS > iOS' 카테고리의 다른 글
iOS) HTTP / HTTPS / RESTful 이 도대체 뭘까 (10) | 2020.12.04 |
---|---|
iOS) 런 루프(RunLoop) 이해하기 (14) | 2020.12.03 |
iOS) Sync vs Async / Serial vs Concurrent (16) | 2020.12.01 |
iOS) 프로세스(Process) vs 쓰레드(Thread) (8) | 2020.12.01 |
iOS) 메모리 저장 방식 - Big Endian / Little Endian (1) | 2020.11.28 |