본문 바로가기
프로그래밍 놀이터/iOS

[iOS Study] 병렬 프로그래밍 가이드 ( operation queue )

by 돼지왕 왕돼지 2017. 7. 2.
반응형

 [iOS Study] 병렬 프로그래밍 가이드 ( operation queue )


https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationObjects/OperationObjects.html#//apple_ref/doc/uid/TP40008091-CH101-SW1


abstract base class, add 된 operation 조작, addDependency, addExecutionBlock, addoperation, addoperations, addOperations:waitUntilFinished, addoperationwithblock, alloc, Argument, attribute, block object, blockOperationWithBlock, Callback, cancel, cancelalloperation, check and modify, circular dependency, completion block, Completion Block 설정하기, concrete class, concurrent, concurrent operation, control, custom operation, default, dependency, DEQUEUE, error propagate, Error 나 Exception 을 다루자, exception, Exception Handling, function, GCD, init, initWithTarget, IOS, isconcurrent, isready, kvo, kvo notification, low priority, lowest priority, main method, main task, No, non-concurrent operation, normal priority, nsblockoperation, nsinvocationoperation, nsinvocationoperation 만들기, NSOperation, nsoperationqueue, Operatino 의 수행을 커스터마이징 하기, Operation, operation object, operation queue, Operation suspending 시키기, operation 간 graph 기반 dependency, Operation 을 실행시키자, Operation 의 수행 priority 조정하기, operationqueue, pause, per-thread storage, Per-thread storage 를 피하자, priority, priority level, programmer error, Queue, queue 에 넣기 전, readiness, Return, selector, semantic, serial, serial dispatch queue, setcompletionblock, setMaxConcurrentOperationCount, setqueuepriority, setsuspended, SetThreadPriority, start, start method, suppress, suspending, system kernel, system level, task, task 수행 상태 감시, taskWithData, thread, thread priority, waituntilfinished, YES, [iOS Study] 병렬 프로그래밍 가이드 ( operation queue ), 기본값, 동시 수행, 병렬 프로그래밍, 수행 순위 결정, 유일한 방법, 주의사항, 키 피쳐, 한 개 이상의 block


Operation Object 에 대한 이야기


-

Operation object 는 NSOperation class 의 인스턴스를 이야기한다.

NSOperation class 는 abstract base class 로 subclass 를 구현해야 한다.



-

NSInvocationOperation 과 NSBlockOperation 이라는 두 가지 형태의 concrete class 도 제공한다.



-

NSInvoationOperation 은 이미 task 를 수행할 function 이 정의되어 있다면 selector 방식으로 해당 function 을 넘기면서 operation 을 생성할 수 있다.



-

NSBlockOperation 은 한개 혹은 그 이상의 block object 를 동시에 수행하도록 할 수도록 하는 operation이다.

여기에 전달된 모든 block 의 수행이 완료되어야 해당 operation 이 완료된 것으로 간주된다.



-

모든 operation object 는 다음과 같은 키 피쳐를 갖는다.


     operation 간 graph 기반의 dependency 를 줄 수 있다. 이 dependency 는 엮여있는 모든 operation 이 끝나야 이 operation 을 수행하도록 한다.

     추가적인 completion block 을 설정할 수 있다. 

     KVO notification 을 이용하여 task 의 수행 상태를 감시할 수 있다.

     priority 를 설정하여 상대적인 수행 순위를 결정하도록 할 수 있다.

     task 수행 중 멈추게 할 수 있는 기능을 추가할 수 있다. ( semantic )




Concurrent vs. Non-concurrent operation


-

보통은 operation 을 만들어 queue 에 넣지만 꼭 그렇게 하지 않아도 된다.

operation 의 start 함수를 바로 호출하여 코드를 수행할 수도 있다.



-

isConcurrent 함수는 operation 이 동기적으로 작동하는지, 비동기적으로 작동하는지를 어떤 thread 에서 start 가 호출되었는지를 기준으로 알려준다.

기본적으로 이 녀석은 NO 를 return 한다.



-

operation 을 수행시키기 위해 thread 를 새로 만들어 그 안에서 start 를 호출할 수 있다.

하지만 보통은 그냥 operation queue 에 넣어주기만 하면 된다.




NSInvocationOperation 만들기


-

NSInvocationOperation 은 전달한 selector 를 수행시키는 기능을 한다.



-

- (NSOperation*) taskWithData:(id)data{

     NSInvocationOperation* op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(myTaskMethod:) object:data];

     return op;

}


- (void)myTaskMethod:(id)data{

     // perform the task

}




NSBlockOperation 만들기


-

NSBlockOperation 은 한개 혹은 그 이상의 block object 를 동시적으로 수행한다.

NSBlockOperation 을 initialize 할 때 한 개 이상의 block 을 전달한다.



-

NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{

     // do some work.

}];



-

initialize 후에는 addExecutionBlock: 을 통해 추가 블럭을 전달할 수 있다.




Custom Operation Object 정의하기, 비동기 수행을 위한 operation 설정


-

이 부분은 우선 생략한다.




Operatino 의 수행을 커스터마이징 하기


-

커스터마이징은 queue 에 넣기 전에 수행되어야 한다.



-

dependency 설정을 할 수 있는데 이는 다른 operation object 와의 serial 한 수행을 control 하는 것을 말한다.

dependency 를 설정하면 해당 operation 들이 종료될 때까지 해당 operation 은 수행되지 않는다.



-

dependency 설정은 addDependency 함수를 통해서 한다.

dependency 는 한개의 queue 에 대해 한정되는 것이 아니라, 서로를 서로 다른 queue 에 넣어도 보장된다.



-

circular dependency 는 programmer error 로 해당 operation 들은 절대 작동하지 않게 된다.



-

dependency 는 KVO notification 을 기반으로 작동하기 떄문에

custom operation 을 사용하는 경우에는 KVO notification 처리를 잘 해주어야 한다.






Operation 의 수행 priority 조정하기


-

queue 에 operation 이 추가되면, readiness 를 기반으로 priority 를 결정한다.

priority level 이라는 attribute 가 있어 이 녀석이 더 결정적으로 작동하여 priority 를 결정한다.


기본적으로 normal priority 를 가지고 있지만, setQueuePriority: 함수를 통해 더 높거나 낮은 priority 를 줄 수 있다.



-

readiness 는 dependency 에 의해 결정이 된다.



-

high priority 라도 ready 되지 않은 녀석은 low priority 의 ready 된 녀석보다 늦게 수행된다.

그래서 dependency 와의 상관관계를 잘 알고 있어야 한다.

( dependency 가 priority attribute 보다 우선한다는 것을 알아야 한다. )




Thread 우선순위 바꾸기


-

기본적인 thread priority 는 system kernel 이 관리한다.

하지만 operation 을 통해 조정도 가능하다.

operation 에 0.0 ~ 1.0 사이로 ( 0.0 이 lowest priority )  thread priority 를 줄 수 있다.

명시하지 않으면 기본인 0.5 로 작동한다.



-

setThreadPriority: 함수를 통해서 priority 를 설정할 수 있다.

해당 함수는 queue 에 넣기 전에 불러야 한다.

start 가 불리는 시점에 priority 를 읽어들여 thread priority 를 조정하게 된다.

단, 해당 operation 의 main method 수행이 끝나면 원래의 priority 로 자동으로 돌아가게 된다.




Completion Block 설정하기


-

OS X v10.6 이상에서는 main task 가 끝날 때 불리는 completion block 을 설정할 수 있다.

setCompletionBlock: 함수를 통해 설정할 수 있다.

전달하는 block 은 argument 나 return 이 없어야 한다.




Per-thread storage 를 피하자


-

보통 operation 이 수행되는 thread 는 system 이 만들어준 녀석이다.

그래서 system 이 이 thread 를 어떻게 관리할 지 모르기 때문에,

per-thread storage 를 사용하는 것은 매우 위험한 것이다.




Error 나  Exception 을 다루자


-

OS X v10.6 이상버전에서는 start method 가 exception 을 잡지 않는다.

하지만 그 전 버전에서는 start method 가 exception 을 잡아 suppress 한다. ( 무시한다. )



-

이제는 operation 에서 발생하는 exception 을 handling 해주어야 한다.

그런데 NSOperation 에는 이 exception 을 handling 해주는 callback 따위가 없기 때문에

task code 안에서 알아서 propagate 하는 방법을 고안해서 수행해야 한다.




Operation 을 실행시키자


-

OperationQueue 는 NSOperationQueue class 를 이용하면 된다.

operation queue 갯수에 대한 제약은 없지만, system level 로 내려가면 결국 한번에 수행될 수 있는 operation 의 수에는 제약이 있다.

그래서 operation queue 갯수를 늘리는 것이 더 많은 concurrent job 을 수행하는 것은 아니다.



-

NSOperationQueue *aQueue = [[NSOperationQueue alloc] init];



-

addOpertion: 함수를 통해 operation 을 추가할 수 있다.

addOperations:waitUntilFinished: 함수를 통해 operation 들을 전달할 수도 있고, ( wait arg 는 YES/NO )

addOperationWithBlock: 을 통해 바로 block object 들을 전달할 수도 있다.



-

queue 에 이미 add 된 operation 은 절대 조작하면 안 된다.

queue 에 들어 있는 녀석은 언제 수행될지 모르기 때문에 check and modify 도 위험할 수 있다.



-

setMaxConcurrentOperationCount: 함수를 통해서 한번에 처리할 operation 수를 정할 수도 있다.

여기에 1 값을 전달하게 되면 serial 한 operation queue 를 만드는 것이다.

단, operation 들은 dependency 라던지 다른 무언가 영향을 미치기 떄문에 GCD 의 serial dispatch queue 와는 조금 다른 구현방식을 보일 수 있다는 것을 알아두어야 한다.




Queue 에 넣지 않고 operation 수행하기


-

start method 를 수행하면 된다.

operation 은 isReady 함수가 YES 를 return 할 때까지 돌지 않는다.

dependency 가 있으면 해당 operation 이 종료될 때까지 YES 를 return 하지 않는다.



-

start method 대신 main 이나 다른 method 를 사용하지 말자!!

start 함수는 그냥 수행이 아닌 몇 가지 다른 일을 하기 때문이다.

예를 들면 KVO notification 을 만든다거나..

이미 cancel 된 상태 혹은 excpetion 을 던진 상태라면 수행하지 않는다거나... 




Operation 취소하기


-

operation 이 한번 queue 에 들어가면 해당 operation 은 queue 에 소속된 녀석이다.

dequeue 하는 유일한 방법은 cancel 하는 것이다.



-

해당 operation 에 cancel 을 때리거나,

cancelAllOperation 을 queue object 에 때려 모두 취소하는 방법만 가능하다.




Operation suspending  시키기


-

setSuspended: method 를 통해서 잠시 queue 의 작업을 중지시킬 수 있다.

이것이 이미 실행된 operatoin 을 pause 시키거나 그렇지는 않는다.




반응형

댓글