GGURUPiOS

동시성 프로그래밍 - Operation 본문

Swift/동시성 프로그래밍

동시성 프로그래밍 - Operation

꾸럽 2023. 4. 24. 14:58

Operation

GCD를 객체지향적으로 새롭게 추가된 API임

GCD와의 차이점은 GCD에서의 코드블럭들(Task)을 캡슐화, 객체화 해낸 것임

객체화의 장점

  • 재사용 용이
  • 타입 간 관계 형성
  • 다양한 프로퍼티 활용
  • 스케쥴링에 용이

Operation

Operation은 추상클래스이기 때문에 이를 상속 받는 타입을 사용해야함

2가지 방법

  • BlockOperation 사용
  • 커스텀 클래스 사용

만들기

BlockOperation은 Operation의 하위 클래스임

let operation = BlockOperation {

}

// addExecutionBlock은 BlcokOperation 메서드임
// 이 메서드는 Operation 동작이 끝난 후 원하는 코드를 실행 해줄 수 있음
operation.addExecutionBlock {

}

// completionBlock 이라는 Operation 프로퍼티에 코드 블럭을 할당하면 Operation과, 그와
// 연관된 executionBlock 들이 모두 실행된 다음, 실행 시킬 수 있음
operation.completionBlock = {

}

Operation 실행

// 직접실행 
operation.start()

// OperationQueue로 실행
let queue = OperationQueue()
queue.addOperation(operation)
 

Operation 프로퍼티

Operation에는 해당 Operation의 상태를 추적할 수 있는 다양한 프로퍼티 존재 ( GCD와의 차이점 )

아래의 Bool 타입 프로퍼티들을 통해 해당 Operation의 상태를 추적할 수 있음

(읽기 전용 프로퍼티)

var isCancelled: Bool
var isExecuting: Bool
var isFinished: Bool
var isConcurrent: Bool
var isAsynchronous: Bool
var isReady: Bool
var name: String?

Operation의 상태 변화

Operation의 상태주기

  • isReady: Operation이 실행될 준비를 마치면 isReady 상태
  • isExecuting: Start가 호출 or OperationQueue에 의해 실행된 후
  • isCancel: Operation을 cancel한 후
  • isFinished: cancel하지 않고 동작을 마침

Cancel

operation.cancel()

Operation은 cancel() 메서드가 있음

그러나, 현재 실행중인 Operation 동작을 강제 취소시켜주지 않으며, isCancelled 프로퍼티 값만 변경해주는 메서드임

isAsynchronous

Operation의 isAsunchronous의 기본값은 false 임

→ 아무런 설정을 해주지 않았다면 동기로 동작함

만약 비동기로 동작하는 Operation이 필요하다면 Custom하여 값을 만들어주어야 함

Dependency (종속성)

Operation 인스턴스들 사이에 종속적인 관계를 만들어서 실행 순서를 관리하도록 함

Operation은 직접 실행한다면 실행순서대로, OperationQueue에 넣는다면 넣은 순서대로 작업을 처리함

addDependency(_:) 메서드로 종속적 관계를 만들어 줄 수 있음

해당 Operation은 자신이 종속된 Operation의 작업이 끝날때까지 실행 불가

위의 코드에서 cherry는 apple에 종속되었음

cherry는 apple의 실행이 끝날 때 까지 실행 불가함

→ 에러 발생

종속성은 addDependency 메서드로 추가해주고, removeDependency 메서드로 제거할 수 있음


OperationQueue

Operation같은 경우는 sync/async 에 대한 정보는 Operation이 가지고 있으며, 스레드 관리는 OperationQueue가 하는 식으로 역할이 분리되어 있음

OperationQueue에서는 모든 Operation에 대해 새로운 스레드를 만들어서 작업을 처리함

OperationQueue는 Operation을 호출함

operation을 큐에 추가하면 실행될 때까지 operation은 큐에 남아 있으며, 직접 삭제 불가

그리고 모든 operation이 끝날 때까지 Queue가 유지되기 때문에, 완료되지 않은 작업을 대기열에 중단 시키면 메모리 누수가 발생할 수 있음 (주의)

OperationQueue 사용하기

OperationQueue의 프로퍼티, 메서드에 대해 알아보자

main, current

// 프로퍼티
class var main: OperationQueue  // 메인 스레드에서 동작하는 OperationQueue반환 ( 메인 스레드에서 작업해야 할 때 사용함 )
class var current: OperationQueue // 현재 작업을 시작한 OperationQueue반환

// 인스턴스 생성
let queue = OperationQueue()
let mainQueue = OperationQueue.main
let currentQueue = OperationQueue.current

addOperation

func addOperation(_ op: Operation)
func addOperations(_ ops: [Operation], waitUntilFinished wait: Bool)
func addOperation(_ block: @escaping () -> Void)

OperationQueue에 Operation을 추가하는 메서드. 추가와 동시에 작업이 수행됨

파라미터에 따라 하나의 Operation, Opeartion배열, 클로저 등 다양한 형태로 추가 가능함

let someOperation = BlockOperation {

}
let operationQueue = OperationQueue()
operationQueue.addOperation(someOperation)

maxConcurrentOperationCount

var maxConcurrentOperationCount: Int

한 번에 최대로 수행되는 작업의 갯수

maxConcurrentOperationCount를 지정해주면 동시에 작업될 수 있는 Operation의 수를 제한해줄 수 있음

cancelAllOpeartions()

대기열에 있는 모든 Operation의 cancel() 메서드를 호출함

→ 실행중인 Operation을 즉각 종료하거나 대기열에서 Operation을 삭제하거나 하지는 않음

waitUntilAllOperationsAreFinished()

현재 스레드를 차단하고 OperationQueue의 모든 Operation 실행이 끝날 때까지 기다리는 메서드임

현재 스레드에 작업 추가는 불가능, 다른 스레드에 작업을 추가는 가능함

DispatchQueue의 wait() 과 비슷한 메서드임

qualityOfService

var qualityOfService: QualityOfService

Operation과 DispatchQueue 모두 QoS를 설정해 우선순위를 설정할 수 있음

isSuspended

var isSuspended: Bool {get set}

대기열이 Operation 스케줄링이 진행중인지에 대한 상태를 나타내는 Bool 값임

false 라면 대기열의 Operation을 실행

true 라면 대기열의 Operation을 실행하지는 않지만 현재 실행중인 Operation은 계속 실행이 됨

true 일 때, 대기열에 Operation을 추가할 수는 있지만 isSuspended가 false가 될 때까지 실행 되지는 않음

Operation은 실행이 완료되어야만 OperationQueue에서 제거가 됨

대기열이 중단된 상태라면 Operation이 완료, 제거되지 못하고 계속 남아있는 상태가 됨 ( 메모리 누수 발생 가능 )