티스토리 뷰

반응형

안녕하세요! Ick입니다~

 

오늘은 OperationQueue를 사용하여 동시성 프로그래밍을 구현하는 것을 해보려고 합니다.

동시성 프로그램의 이론적인 내용은 여기를 참고해주세요!

 

우선 iOS에서 동시성 프로그래밍을 구현할 때 사용하는 큐에는 DispatchQueue와 OperationQueue가 있습니다.

DispatchQueue의 사용법을 알고 싶으시다면 여기를 참고해주세요!

 

두 큐 모두 동시성 프로그래밍을 구현할 때 사용되지만 이번에 사용할 OperationQueue는 Operation이라는 객체로 작업이 수행됩니다.

또한 OperationQueue를 사용하면 작업 객체들 간 종속성을 부여하여 작업의 순서를 정해줄 수 있습니다!

이 두 가지가 가장 큰 차이점이라고 생각합니다!

 

Operation객체를 만들어서 실행하는 방법에는 두 가지 방법이 있습니다.

작업 객체 자체에서 start 메서드를 사용하여 실행하는 방법과 OperatingQueue를 사용해서 실행하는 방법입니다.

start 메서드를 호출하여 실행하면 호출한 스레드에서 작업을 실행합니다. 이땐 동기적으로 실행됩니다.

하지만 OperatingQueue를 사용하여 실행하면 비동기적으로 실행됩니다.

let blockOperation1 = BlockOperation {
    for _ in 0..<5{
        print("😆")
    }
}

let blockOperation2 = BlockOperation {
    for _ in 0..<5{
        print("❤️")
    }
}

blockOperation1.start()
blockOperation2.start()

위와 같이 동기적으로 실행됩니다.

그렇다면 OperationQueue에 넣어서 실행하면 어떨까요?

let blockOperation1 = BlockOperation {
    for _ in 0..<5{
        print("😆")
    }
}

let blockOperation2 = BlockOperation {
    for _ in 0..<5{
        print("❤️")
    }
}

let myQueue = OperationQueue()
myQueue.addOperation(blockOperation1)
myQueue.addOperation(blockOperation2)

위와 같이 직접 큐를 만들어서 작업 객체를 실행하면 위의 결과와 같이 비동기적으로 수행되는 것을 볼 수 있습니다!

 

그럼 Operation객체들에 종속성들을 주며 실험을 해보겠습니다.

종속성을 간단하게 알아보고 넘어갈게요..

종속성(Dependency)

종속성은 A 작업이 끝나면 B 작업을 수행하겠다고 하는 관계를 나타냅니다.

예를 들어 치킨집에서 하는 일이 치킨 튀기기, 주문받기, 치킨 배달이라는 3가지만 존재할 때

주문을 받은 뒤에 치킨을 튀겨야 하는 것처럼 작업에 순서가 있을 때 종속성을 추가하여 순서를 제어할 수 있습니다.

 

바로 구현해보며 결과를 확인해볼게요!

let blockOperation1 = BlockOperation {
    for _ in 0..<5{
        print("😆")
    }
}

let blockOperation2 = BlockOperation {
    for _ in 0..<5{
        print("❤️")
    }
}

let myQueue = OperationQueue()
// 종속성 부여
blockOperation1.addDependency(blockOperation2)

blockOperation1.start()
blockOperation2.start()

위와 같이 코드를 짜서 실행하면 어떻게 될까요??

지금 상황은 blockOperation1은 blockOperation2가 끝날 때 까지는 실행되지 못하는 상황입니다.

종속성이 부여됐기 때문인데요!

위의 코드처럼 실행하면 동기적으로 실행되는 것을 아까 위에서 확인했죠!?

그래서 위의 코드는 오류가 발생합니다.

blockOperation1이 절대 실행될 수 없기 때문에 발생하는 오류죠!

따라서 이럴 땐 OperationQueue를 사용해줘야 합니다!

let blockOperation1 = BlockOperation {
    for _ in 0..<5{
        print("😆")
    }
}

let blockOperation2 = BlockOperation {
    for _ in 0..<5{
        print("❤️")
    }
}

let myQueue = OperationQueue()
// 종속성 부여
blockOperation1.addDependency(blockOperation2)

myQueue.addOperation(blockOperation1)
myQueue.addOperation(blockOperation2)

 

이렇게 하면 위와 같이 결과가 나오는 것을 알 수 있어요!

예를 들어 순서를 정해주고 싶은 작업들이 있을 때 위와 같이 종속성을 부여해서 수행하면 좋을 것 같아요

let blockOperation1 = BlockOperation {
    print("이게 제일 마지막에 수행되어야 합니다")
}

let blockOperation2 = BlockOperation {
    print("이건 제일 먼저 수행되어야 하구요")
}

let blockOperation3 = BlockOperation{
    print("이건 2번째로 수행되면 좋겠어요")
}

let myQueue = OperationQueue()
blockOperation1.addDependency(blockOperation3)
blockOperation3.addDependency(blockOperation2)
myQueue.addOperation(blockOperation1)
myQueue.addOperation(blockOperation2)
myQueue.addOperation(blockOperation3)

위와 같이 코드를 짜면 종속성을 사용해서 프로그램이 수행되는 순서를 제어할 수 있게 됩니다!

 

작업 객체에는 우선순위도 부여할 수 있는데요 우선순위는 다음과 같이 존재합니다.

아주 직관적으로 우선순위를 알 수 있는 거 같아요 ㅋㅋㅋ

이걸 사용해서 작업들을 만들어서 실행해보겠습니다.

let highPriorityOperation = BlockOperation {
    for _ in 0..<5{
        print("우선순위 높은 작업🎖")
    }
}
highPriorityOperation.queuePriority = .veryHigh

let lowPriorityOperation = BlockOperation {
    for _ in 0..<5{
        print("우선순위 낮은 작업🍭")
    }
}
lowPriorityOperation.queuePriority = .veryLow

lowPriorityOperation.start()
highPriorityOperation.start()

이렇게 start 메서드로 실행하면 동기적으로 실행되기 때문에 위와 같이 우선순위가 극단적으로 차이가 나더라도 먼저 실행한 게 먼저 완료됩니다.

let highPriorityOperation = BlockOperation {
    for _ in 0..<5{
        print("우선순위 높은 작업🎖")
    }
}
highPriorityOperation.queuePriority = .veryHigh

let lowPriorityOperation = BlockOperation {
    for _ in 0..<5{
        print("우선순위 낮은 작업🍭")
    }
}
lowPriorityOperation.queuePriority = .veryLow

let myQueue = OperationQueue()
myQueue.addOperation(lowPriorityOperation)
myQueue.addOperation(highPriorityOperation)

그래서 위와 같이 큐를 사용해서 실행하면...

기대와는 달리 우선순위가 낮은 작업이 먼저 완료됐다.

???

공식문서를 읽어볼게요..

위와 같이 나와있는데 결론은 어떤 작업들 간에 순서를 주고 싶다면 종속성을 사용하라는 것이다.

DispatchQueue에서는 우선순위에 따라 완료되는 순서도 달랐는데 OperationQueue는 다른가보다.

혹시나 해서 maxConcurrentOperationCount라는 동시에 수행 가능한 작업의 개수를 수정해서 실행해봤지만..

let highPriorityOperation = BlockOperation {
    for _ in 0..<5{
        print("우선순위 높은 작업🎖")
    }
}
highPriorityOperation.queuePriority = .veryHigh

let lowPriorityOperation = BlockOperation {
    for _ in 0..<5{
        print("우선순위 낮은 작업🍭")
    }
}
lowPriorityOperation.queuePriority = .veryLow

let myQueue = OperationQueue()
// 동시에 수행할 큐 개수
myQueue.maxConcurrentOperationCount = 2
myQueue.addOperation(lowPriorityOperation)
myQueue.addOperation(highPriorityOperation)

결과는 차이가 없었습니다.

아 그리고 maxConcurrentOperationCount 값을 1로 줄이면 동시에 1개의 작업만 수행할 수 있게 되므로 OperationQueue를 사용하더라도 동기적으로 실행되게 된답니다.

 

이렇게 OperationQueue를 사용해서 동시성을 구현해봤습니다!

감사합니다~

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
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
글 보관함