이 블로그 검색

2011년 3월 24일 목요일

Intro to Grand Central Dispatch, Part I: Basics and Dispatch Queues 정리


참고 : www.mikeash.com

향후 아이패드2나 아이폰5 등 멀티코어 환경에서 개발을 하려는 사람들에게는
꼭 알아두어야 할 기술이 바로 이 GCD 가 아닐까 한다.

* 2011-10-20에 추가됨
이번에 IOS5 가 나오면서 GCD 에 변경된 부분이 있다.
간추려보면
1. 새로운 global queue 추가(DISPATCH_QUEUE_PRIORITY_BACKGROUND)
2. custom concurrent queue
3. Dispatch IO
자세한 사항은 여기를 참조

1. GCD (Grand Central Dispatch)

concurrent programming을 위한 저수준 C API.
작업을 분리하고 work queues에 저장후, 동시에 혹은 하나씩 작업을 처리.
(NSOperationQueue와 비슷하나 좀더 저수준이고 높은 성능을 보인다고 한다).

dispatch object =  GCD 는 객체지향 개념으로 만들어졌다. GCD 객체를 일컬음.

메모리 관리 필요 : dispatch_retain, dispatch_release

Dispatch Queues: 처리할 작업을 받아들이기 위한 객체. concurrent / serial 이 존재.
동시에 작업을 처리(시스템 부하를 고려하여)하거나 하나씩 작업을 처리한다.

3가지 큐 존재

Main queue: serial queue.
메인 쓰레드가 처리하게 된다.
dispatch_get_main_queue() 호출로 얻을수있다. 

Global queues: concurrent queues
전체 프로세스가 공유하며, 3종류 존재
(high,default,low priority queue).
동시에 작업을 수행한다.
dispatch_get_global_queue() 호출로 접근가능 (priority 지정필요).

Custom queues: serial queue.
한번에 하나씩 작업을 처리한다.
dispatch_queue_create()로 생성된다.

2. 사용법
  1) 큐를 생성 (위의 함수 호출 이용)
custom queue 경우 다음처럼 호출.

1
dispatch_queue_create("com.yourcompany.subsystem.task", NULL);
Pastie #2500485 linked directly from Pastie.
 
  2) 처리할 작업을 전달한다.
       
1
2
3
4
5
6
dispatch_async(dispatch_get_global_queue
  (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
 ^{
  [self goDoSomethingLongAndInvolved];
  NSLog(@"Done doing something long and involved");
 });
Pastie #2500430 linked directly from Pastie.
dispatch_async 함수는 즉시 리턴되며, 작업은 비동기적으로
백그라운드에서 수행된다.

* 중첩된 dispatche.
시간이 걸리는 작업 종료후 UI변경등이 필요한 경우
UI처리는 main thread 에서 수행되어야 하므로 중첩된 호출을 통해 가능함.
       
1
2
3
4
5
6
7
8
9
dispatch_async(dispatch_get_global_queue
  (DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
^{
 [self goDoSomethingLongAndInvolved];
     dispatch_async(dispatch_get_main_queue(),
     ^{
            [textField setStringValue:@"Done doing something long and involved"];
        });
});
Pastie #2500436 linked directly from Pastie.
처리할 작업(block)이 종료될때까지 기다리는 경우 dispatch_sync 사용.
__block 변수 : 살행중인 block으로부터 결과를 받을수 있음. 만약 백그라운드
작업중인 쓰레드에서 GUI 컴트롤 값을 필요로 하는 경우 다음처럼 사용가능.
       
1
2
3
4
5
6
7
8
9
10
11
12
13
//백그라운드 쓰레드내에서의 소스.
//현재 이쓰레드가 백그라운드로 작업중이라고 가정.
__block NSString *stringValue;
  
dispatch_sync(dispatch_get_main_queue(),
^{
        // __block 변수는 자동으로 retain 되지 않음.
        // reference 를 확실하게 만들어서 관리한다.
        stringValue = [[textField stringValue] copy];
});
  
[stringValue autorelease];  
// 그리고 stringValue를 백그라운드 쓰레드에서 사용한다.
Pastie #2500450 linked directly from Pastie.

쓰레드등을 이용한 백그라운드 프로세싱을 중첩된 block을 이용하여 아래처럼
교체가능하다.

1
2
3
4
5
6
7
8
9
dispatch_queue_t bgQueue = myQueue; //global 혹은 custom 큐.

dispatch_async(dispatch_get_main_queue(), ^{
    NSString *stringValue = [[[textField stringValue] copy] autorelease];
    dispatch_async(bgQueue, ^{
            // 이부분에 들어가는 소스는 백그라운드로 수행되며
            // stringValue 를 사용할수 있다.
    });
});
Pastie #2500459 linked directly from Pastie.
 3) Lock을 대체하기 위해서 이렇게도 사용 가능하다.
      일반적인 경우가 다음과 같다면,
   
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
NSLock *lock;  
//getter
- (id)something
{
    id localSomething;
    [lock lock];
    localSomething = [[something retain] autorelease];
    [lock unlock];
    return localSomething;
}
//setter
- (void)setSomething:(id)newSomething
{
    [lock lock];
    if(newSomething != something)
    {
        [something release];
        something = [newSomething retain];
        [self updateSomethingCaches];
    }
    [lock unlock];
}
Pastie #2500472 linked directly from Pastie.
   
     다음처럼 바꿀수 있다.
     이때 큐는 custom (즉 serial)큐만 가능하다. 동기 /비동기 처리를
활용하는것임. 즉 , 비동기(dispatch_async)로 동기화가 필요한 함수를
호출하면  백그라운드에서는 dispatch_sync로 처리되어 serial하게
작업을 처리한다.
   
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- (id)something
{
    __block id localSomething;
    dispatch_sync(queue, ^{
         localSomething = [something retain];
    });
    return [localSomething autorelease];
}
    
- (void)setSomething:(id)newSomething
{
    dispatch_async(queue, ^{
        if(newSomething != something)
        {
            [something release];
            something = [newSomething retain];
            [self updateSomethingCaches];
        }
    });
}
Pastie #2500480 linked directly from Pastie.
        
dispatch queue 사용이 매우 가벼워서 lock을 거는 빈도가 많아도 무방함. 


더욱 온전한 내용을 원하신다면 원문을 참조하기 바랍니다...

댓글 없음:

댓글 쓰기