GCD는 작업을 비동기적으로 실행하기 위한 기술 중 하나다. 이 기술은 보통 개발자들이 응용프로그램을 만들 때 직접 작성하는 스레드 관리 코드를 GCD자체가 관리하기 때문에 전통적인 멀티스레드 프로그래밍 방법보다 훨씬 쉽게 멀티 스레딩을 지원할 수 있도록 하였다.

GCD가 만들어지기 전에는 NSObject 인스턴스 메서드인 performSelectorInBackground:withObject, performSelectorOnMainThread등을 사용했다. 
performSelector계열이 NSThread 클래스를 사용한 코드보다는 쉽지만, GCD를 이용한 코드가 확실히 가장 쉽다. 게다가 훨씬 효율적이다.


CPU가 응용프로그램을 실행하는 방식
- 소스코드는 실행되기전 CPU 바이트코드로 변환된다. 응용프로그램은 맥이나 아이폰에 설치될 데이터와 바이트코드를 하나로 묶는다. 운영체제가 바이트 코드를 메모리에 할당하고 응용프로그램에 명시된 특정 주소를 시작으로 CPU가 바이트 코드를 한줄 한줄 실행한다.

하나의 CPU는 한 순간에 하나의 명령을 수행할 수 있다. 즉 한 순간에는 하나의 스레드만 작업할 수 있다는 얘기이다.
그렇다면 응용프로그램은 어떻게 멀티 스레딩을 지원할 수 있을까? 그것은 커널이 일정 간격으로 각 스레드를 스위치시키고, 시스템 콜 같은 OS 이벤트가 발생하면 실행중인 스레드의 실행상태를 각 스레드에 할당된 메모리 블록 중 하나에 저장한다. 즉, 이를 반복해서 CPU가 여러 경로를 실행하는 것처럼 동작한다. 이런 방식을 문맥 전환(context switch)라고 한다.
멀티 스레드 프로그램은 컨텍스트 스위치를 끊임없이 반복한다. 그러므로, 하나의 CPU가 가상으로 여러 스레드를 실행할 수 있게 된다. 여러개의 CPU 코어가 있을 때는 각 코어가 동시에 스레드를 실행할 수 있다. 즉, 실제로 스레드가 동시에 실행될 수 있는 개수가 CPU 코어의 개수이다.


GCD  기본
디스패치 큐(Dispatch Queues)
- 디스패치 큐는 실행할 작업을 저장하는 큐이다. dispatch_async 함수를 사용하여 작업들을 디스패치 큐에 추가할 수 있다.
- 디스패치 큐는 두가지 종류가 있다. 하나는 시리얼 디스패치 큐(serialDispatchQueue)이고 나머지 하나는 콘커런트 디스패치 큐(concurrentDispatchQueue)이다. 시리얼 디스패치 큐는 작업을 큐에 들어온 순서대로 동작시키고 콘커런트 디스패치 큐는 들어온 작업들을 비동기적으로 실행시킨다. 즉, 시리얼 디스패치 큐는 단일 스레드를 사용하고 콘커런트 디스패치 큐는 멀티 스레드를 사용한다.
다만 콘커런트 디스패치 큐는 작업 하나마다 스레드 하나를 할당하는 것이 아니라 커널이 스레드의 갯수를 정해주고 각 스레드가 작업을 분담해서 나눠서 처리한다.

디스패치 큐 얻기
- dispatch_queue_create
: 새로운 디스패치 큐를 생성한다.

dispatch_queue_t mySerialDispatchQueue = dispatch_queue_create("com.hsg2510.MySerialDispatchQueue", NULL);
// 디스패치 큐의 이름은 프로그램 내에서 유일해야 되기 때문에 도메인 역순 표기법을 추천한다. 

시리얼 디스패치 큐가 만들어지고 작업이 추가될 때, 시스템은 각각의 시리얼 디스패치 큐를 위해 하나의 스레드를 생성한다. 
디스패치 큐는 Objective-c 객체로 취급되지 않기 때문에 수동으로 릴리스하기 위해 dispatch_release를 호출해 줘야 한다.

dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("com.hsg2510.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(myConcurrentDispatchQueue, ^{ NSLog(@"hi~") });
dispatch_release(myConcurrentDispatchQueue);
// 디스패치 큐에서 작업이 실행되고 작업이 끝나기를 기다리지 않고 바로 release한다. 괜찮은가? 괜찮다. 작업 블록이 dispatch_async 함수에 의해 디스패치 큐에 추가 되었을 때 작업블록이 dispatch_retain함수에 의해서 디스패치 큐의 소유권을 갖는다. 그리고 블록의 실행이 종료되었을 때, 블록은 dispatch_release함수에 의해서 디스패치 큐가 릴리즈된다.

- 메인 디스패치 큐 / 글로벌 디스패치 큐
: 디스패치 큐를 얻는 다른 방법은 시스템이 이미 제공하고 있는 디스패치 큐를 가져오는 것이다. 시스템은 당신이 생성 못하는 메인 디스패치 큐와 글로벌 디스패치 큐를 갖고있다.
메인 디스패치 큐는 메인 스레드에서 작업을 실행하는 큐이다. 이것은 시리얼 디스패치 큐이고 이 큐에 할당된 작업들은 메인 스레드의 RunLoop에서 실행된다.
글로벌 디스패치 큐는 콘커런트 디스패치 큐이다. 실제로 정말 특별한 경우가 아니라면 dispatch_queue_create함수를 사용하여 콘커런트 디스패치 큐를 생성할 필요가 없다. 이미 시스템은 4개의 글로벌 디스패치 큐가 있고 그것들은 각기 다른 중요도(high, default, low, background)를 가지고 있다. 


'IOS > Objective-C' 카테고리의 다른 글

ARC 규칙  (0) 2017.01.01
GCD(Grand Central Dispatch)(2)  (0) 2016.12.19
Objective-C의 동적 바인딩, 그리고 Message dispather와 Runtime  (0) 2016.12.18
Key-Value Coding(1)  (0) 2016.12.07
Collections의 weak reference  (0) 2016.10.02
Posted by 홍성곤
,