[iOS] NSOperationQueue 직렬처리 알아보기

  NSOperationQueue 직렬처리 알아보기


멀티쓰레드 환경에서 async 처리로 네트워크 처리를 진행하는데 어쩔수 없이 직렬로 보내야 하는 경우가 있다.

필자의 경우 그룹웨어의 대화방 이라는 메뉴가 그렇다.

NSOperationQueue 관련 링크 (세부적인 내용이 많아서 공유합니다.)
참조 : https://code-examples.net/ko/q/1001a9


  1. NSOperationQueue 단독 직렬처리 테스트

* maxConcurrentOperationCount 의 따라 동시에 실행되는 Operation이 조정된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import UIKit
// 1. NSOpertaionQueue 생성 (병렬 진행 1)
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1 // 2 이상부터는 언제나 실행 순서가 바뀜 (테스트시 변경)
let operation1 = BlockOperation {
    print("Operation 1 실행")
}
let operation2 = BlockOperation {
    print("Operation 2 실행")
}
let operation3 = BlockOperation {
    print("Operation 3 실행")
}
let operation4 = BlockOperation {
    print("Operation 4 실행")
}
let waitOperation = BlockOperation {
    print("실행하지 않는 Operation")
}
// 수신자의 모든 종속 작업이 실행 마칠 때까지 실행한 준비가 된 것으로 간주되지 않음. (wait을 실행 Quque에 넣지 않았음.)
operation2.addDependency(waitOperation)
//queue.addOperations([operation1,operation2,operation3,operation4], waitUntilFinished: false)
queue.addOperation(operation1)
queue.addOperation(operation2)
queue.addOperation(operation3)
queue.addOperation(operation4)
// 결과
//Operation 1 실행
//Operation 3 실행
//Operation 4 실행
cs


  2. NSOperationQueue in GCD 직렬처리 점검

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import UIKit
// 1. NSOpertaionQueue 생성 (병렬 진행 1)
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1 // 2 이상부터는 언제나 실행 순서가 바뀜 (테스트시 변경)
let operation1 = BlockOperation {
    print("Operation 1 실행")
    DispatchQueue.main.async {
        print("Opertaion 1 속 dispatch")
    }
}
let operation2 = BlockOperation {
    print("Operation 2 실행")
    DispatchQueue.main.async {
        print("Opertaion 2 속 dispatch")
    }
}
let operation3 = BlockOperation {
    print("Operation 3 실행")
    DispatchQueue.main.async {
        print("Opertaion 3 속 dispatch")
    }
}
let operation4 = BlockOperation {
    print("Operation 4 실행")
    DispatchQueue.main.async {
        print("Opertaion 4 속 dispatch")
    }
}
let waitOperation = BlockOperation {
    print("실행하지 않는 Operation")
    DispatchQueue.main.async {
        print("Opertaion 5 속 dispatch")
    }
}
// 수신자의 모든 종속 작업이 실행 마칠 때까지 실행한 준비가 된 것으로 간주되지 않음. (wait을 실행 Quque에 넣지 않았음.)
operation2.addDependency(waitOperation)
//queue.addOperations([operation1,operation2,operation3,operation4], waitUntilFinished: false)
queue.addOperation(operation1)
queue.addOperation(operation2)
queue.addOperation(operation3)
queue.addOperation(operation4)
// 결과
//Operation 1 실행
//Operation 3 실행
//Operation 4 실행
//Opertaion 1 속 dispatch
//Opertaion 3 속 dispatch
//Opertaion 4 속 dispatch
cs


  3. NSOperationQueue in GCD, DispatchSemaphore 직렬처리

* 앞서 2번의 결과를 참조하면 Quque 까지는 직렬로 처리되지만, 그 내부의 GCD는 또 그렇지 않다.
추가적으로 GCD를 제어할 수 있는 Semaphore를 사용한 직렬처리 테스트 이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
import UIKit
// 1. NSOpertaionQueue 생성 (병렬 진행 1)
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1 // 2 이상부터는 언제나 실행 순서가 바뀜 (테스트시 변경)
// 세마포어 활용
let semaphore = DispatchSemaphore(value: 0)
let operation1 = BlockOperation {
    
    print("Operation 1 실행")
    
    DispatchQueue.main.async {
        print("Opertaion 1 속 dispatch Quque Count : \(queue.operationCount)")
        semaphore.signal()
    }
    semaphore.wait()
}
let operation2 = BlockOperation {
    print("Operation 2 실행")
    DispatchQueue.main.async {
        print("Opertaion 2 속 dispatch Quque Count : \(queue.operationCount)")
        semaphore.signal()
    }
    semaphore.wait()
}
let operation3 = BlockOperation {
    print("Operation 3 실행")
    DispatchQueue.main.async {
        print("Opertaion 3 속 dispatch Quque Count : \(queue.operationCount)")
        semaphore.signal()
    }
    semaphore.wait()
}
let operation4 = BlockOperation {
    print("Operation 4 실행")
    DispatchQueue.main.async {
        print("Opertaion 4 속 dispatch Quque Count : \(queue.operationCount)")
        semaphore.signal()
    }
    semaphore.wait()
}
let waitOperation = BlockOperation {
    print("실행하지 않는 Operation")
    DispatchQueue.main.async {
        print("실행하지 않는 Operation 속 dispatch")
        semaphore.signal()
    }
    semaphore.wait()
}
// 수신자의 모든 종속 작업이 실행 마칠 때까지 실행한 준비가 된 것으로 간주되지 않음. (wait을 실행 Quque에 넣지 않았음.)
operation2.addDependency(waitOperation)
let array = [operation1, operation2, operation3, operation4]
queue.addOperations(array, waitUntilFinished: false)
// 결과
//Operation 1 실행
//Opertaion 1 속 dispatch Quque Count : 4
//Operation 3 실행
//Opertaion 3 속 dispatch Quque Count : 3
//Operation 4 실행
//Opertaion 4 속 dispatch Quque Count : 2
cs


  마무리

이번에 NSOperationQueue의 직렬처리 테스트를 진행하였는데, 보통 Queue에 담아도 내부적으로 실행되는 네트워크 통신 등은 보통 클로져(or 블럭) 으로 되어있어서 GCD Semaphore 테스트 까지 진행해 보았다. 이번에 업무중에 이를 통해 개선을 하였고, 남용하지 않고 관리를 잘해보아야 할 것 같다.

끝.

댓글

이 블로그의 인기 게시물

[iOS] 앱스토어 등록 전, 후 URL 알아보기

[Xcode] add Simulators (시뮬레이터 추가하기)

[iOS] 앱 아이콘 동적으로 변경하기 (Dynamically Change App icon)

[iOS] Device Name 가져오기 (for Swift) - 2022/09/22 update

[iOS] sizeToFit vs sizeThatFits 알아보기