"본 내용은 인프런강의를 들으며 DispatchQueue와 Operation에 대해 간단하게 정리한 글 입니다."
GCD | Operation |
---|---|
Grand Central Dispatch = Dispatch Queue | Operation Queue |
- 간단한 일(커뮤니케이션의 양) | - 복잡한 일(커뮤니케이션의 양) |
- 함수를 사용하는 작업(메서드 위주) | - 데이터와 기능을 캡슐화한 객체 |
Operation이라는 개념은 GCD의 개념을 기반으로 여러가지 기능이 더해져서 만들어진 개념이다.
//Queue로 클로저를 보낸다. 글로벌큐에(initializer). 비동기적으로
DispatchQueue.global().async {
작업한 내용을(클로저)
}
// 보낼 queue의 종류를 선언
let queue = DispatchQueue.global()
// 해당 queue에 비동기적으로 보낼 것이다.
queue.async {
클로저(closure)를
}
// 작업의 단위 ===> "하나의 클로저" 안에 보내는 작업 자체가 묶이는 개념
DispatchQueue.global().async {
print("Task1 시작")
print("Task1 의 중간작업 1")
print("Task1 의 중간작업 2")
print("Task1 의 중간작업 3")
print("Task1 의 중간작업 4")
print("Task1 의 중간작업 5")
print("Task1 종료")
}
메인 thread가 다른 thread에서 작업을 하도록 시킨 후 해당 작업이 끝나길 기다리지 않고 다음 작업을 진행한다.
→ 메인 thread가 다른 일 처리를 시작할 수 있다.
메인 thread가 다른 thread에서 작업을 하도록 시킨 후 해당 작업이 끝날 때 까지 기다렸다가 다음 작업을 진행한다.
→ 작업이 끝나기 전까지 메인 thread는 다른 일처리를 시작할 수 없다.
대부분은 서버와의 통신(네트워크 작업) 때문에
보통 메인 thread에서) 분산처리 시킨 작업을 다른 한개의 thread에서 처리하는 queue
(보통 메인 thread에서) 분산처리 시킨 작업을 다른 여러개의 thread에서 처리하는 queue
분산처리 하려면 Concurrent Queue가 무조건 좋아 보이는 것 같은데
왜 serial queue가 필요할까?
직렬(Serial Queue) | 동시(Concurrent Queue) |
---|---|
순서가 중요한 작업을 처리할 때 사용 | 각자 독립적이지만 유사한 여러개의 작업을 처리할 때 사용 |
동시작업이 필요한 경우:
컬랙션 뷰에서 독립적인 이미지 를 처리하지만 동시적으로 처리되어야 유저가 불편함을 느끼지 않고 스크롤을 통해 컨텐츠를 확인할 수 있게 된다.
Dispatch Queue에는 여러가지 대기열이 있다.
대기열마다 특성이 다르기 때문에 작업의 특성, 원하는 일처리에 따라 대기열(Queue)의 특성에 맞게 작업을 보내면 된다.
원하는 Queue로 작업을 보내면 각 Queue가 각자 다른 thread를 생성하고 일을 처리하게 된다.
DispatchQueue.main.async {
}
우리가 기본적으로 실행하는 코드는 직렬 + 동기적으로 실행되어왔던 것이다.
우리가 평소에 print("print something")
라고 사용했던 메서드에는 아래와 같은 의미가 숨겨져 있던 것이다.
DispatchQueue.main.sync {
print("print something")
}
DispatchQueue.global().async {
}
GlobalQueue에는 총 6가지의 Queue가 존재한다.
Queue의 우선순위
iOS가 알아서 우선 순위에 있는 Queue의 작업이 더 중요한임을 인지하고 thread에 우선순위를 매겨 더 여러개의 thread를 배치하고 배터리를 더 집중해서 사용하도록 한다.
Default setting: Serial
Concurrent setting available
Qos setting available
OS가 QoS를 알아서 추론한다
let queue - DispatchQueue(label: "customName")
let queue1 = DispatchQueue(label: "customName2", attributes: .concurrent)
그렇기에 유저가 빠르게 스크롤을 할 때 이미 지나간 셀의 이미지를 실제로 표시할 필요가 있을까에 대한 고민:
빠르게 스크롤을 해서 이미 지나간 이미지에 대한 다운로드 하는 작업을 취소해야하지 않을까?
Operation과 Operation의 개념을 통해 이런 부분을 해소할 수 있다.
Class화 된 작업
단위(패키지) 작업, 클래스화한 작업
기존에는 메서드와 같은 것들을 GCD를 통해서 작업을 클로저 안에 넣어서 보냈는데 작업 자체가 class화 되어서 해당 인스턴스를 이용하는 것이 Operation이다.
기본적으로 동기적으로 설정 [Sync]
인스턴스화해서 사용하고 → 작업 한번만 실행가능 (원하면 다시 객체를 생성해야 한다.)
단위적인 작업을 클래스화 해서 기능을 향상 시키는 것
Operation의 메서드 및 변수
이런 상태 체크가 필요한 이유: Operation Queue가 궁극적으로 순서를 지정하거나 작업을 취소하기 위해서 위와 같은 bool 변수를 내장하고 있다.
Operation이란 애플에서 만든 추상적인 클래스다. 이를 개발자가 사용하기 위해서는 Operation을 상속 받아서 사용해야 한다.
개발자는
해야 햔다.
class AnOperation: Operation {
var inputImage: UIImage?
var outputImage: UIImage?
override func main() {
// 정의해야 하는 메서드 내용
}
// 객체 생성 후 사용
let op = AnOperation
}
몇 개의 thread를 사용할 것인지 구체적 설정 가능
QoS 설정 가능
기본 설정은 .background
Queue.qualityOfService = 원하는 품질 설정
Operation 자체의 품질을 설정하면, Queue의 품질이 승격될 수 있다
기반이 되는 디스패치큐까지 설정이 가능하고 이는 가장 우선적으로 적용된다.
Operation 추가 방법
클로저, operation, operation 배열 추가 가능(waitUntilFinished 아규먼트 존재)
(Operation을 Operation queue에 넣었을 때는 thread에 배치되었을 때 바로 isExecuting 상태가 된다.) start() 메서드 필요 없음
Operation이 한번 실행되거나, 취소되면 Operation Queue를 떠난다.
동기적으로 기다리는 메서드 존재 waitUntilAllOperationsAreFinished()
기능: 일시중지- 재개 가능
let operationQueue = OperationQueue()
operationQueue.addOperation(특정 Operation)
// 또는
operationQueue.addOperations([operation 배열], waitUntilFinished: true)
여러개의 operation을 전달하고 모든 operation이 끝날 때까지 기다린다.
*block == closure
Operation을 많이 사용하는 앱에서, GCD와 같이 더 단순한 클로저가 필요한 경우에 사용
let blockOperation = BlockOperation()blockOperation.addExecutionBlock {// 추가적으로 더할 수 있는 작업}let blockOperation = BlockOperation { result = 2 + 3}// 모든 block작업이 끝난 뒤 실행할 completion 정의blockOperationlcompletionBlock = { print("===모든 출력 완료!===")}
[출처]: