본문 바로가기
Xcode/Swift - PlayGround

PlayGround) Opeation Queue - 1

by 후르륵짭짭 2022. 1. 17.
728x90
반응형

안녕하세요! 후르륵짭짭입니다.

하,,, 정말 블로그 쉽지 않네요 ㅠㅠ

일도 해야하고, 공부도 해야하고, 쉬기도 해야하는데 ㅠㅠ

블로그 작성 까지 하려니 쉽지 않습니다.

점점 블로그 퀄리티가 나빠지는 것 같은데, 이해 좀 부탁드리겠습니다.

 

** 단순한 BlockOpeation ** 

//it will block the main thread since operation.start() was called on main thread
//Operation objects execute in a synchronous manner by default
let operatoin = BlockOperation {
    for i in 0...10 {
        print("hello \(i)")
        print(Unmanaged.passUnretained(Thread.current).toOpaque())
        print(Thread.isMainThread)
    }
}

operatoin.start()

현재 opeation은 메인 Thread에 있으니 Main Thread 위에서 작업하게 됩니다.

즉 start()가 호출 되는 시점의 Thread에서 블록오퍼레이션이 작업 할 겁니다.

 

** 전체는 순차적으로! 내부는 비동기적으로 **

//Operation의 ExecuteBlock 자체들은 비동기적으로 작동하지만
//Operation 외부의 것은 동기적으로 작동한다.
//따라서 BlockOperation이 끝나야 다음 작업을 시작한다.
let ourOperation = BlockOperation()

ourOperation.addExecutionBlock {
    for i in 0...10{
        print("Hello\(i)")
    }
}

ourOperation.addExecutionBlock {
    for i in 0...10{
        print("World\(i)")
    }
}

ourOperation.addExecutionBlock {
    for i in 0...10{
        print("짭짭\(i)")
    }
}

ourOperation.start()

print("This will called when 'Hello' and 'World' executed")

for i in 0..<10{
    print("End\(i)")
}

ourOperation을 생성하고 작업들을 생성해주고 start()를 해줬습니다.

이렇게 해주면 내부적으로는 비동기적으로 작업하지만 

외부적으로는 순차적으로 작업하게 되어 

 BlockOperation => This will called ,,,, => End(0~9) 

이렇게 순차적으로 수행 됩니다.

 

** 그럼 비동기적으로 수행하자 **

//이렇게 다른 쓰레드로 할 경우
//비동기적으로 작업을 할 수 있게 한다.
//하지만 같은 쓰레드에 있는 것은
//동기화 작업을 하게 된다.
let ourOperationOtherThread = BlockOperation()
ourOperationOtherThread.addExecutionBlock {
    for i in 0 ... 10 {print("Hello \(i)")}
}
ourOperationOtherThread.addExecutionBlock {
    for i in 0 ... 10 {print("짭짭 \(i)")}
}
DispatchQueue.global(qos: .background).async {
    print("Running on Thread : \(Thread.current)")
    ourOperationOtherThread.start()
    print("ourOperationOtherThread.start() \(Thread.current) will block me please help")

    for i in 0..<10{
        print("End\(i)")
    }

}
print("This will called now")

 

** CompletionBlock으로 작업 마칠 때를 알자 ** 

//completion block을 추가해서
//언제 Operation이 끝나는지 추론할 수 있다.
let ourOperationCompletionBlock = BlockOperation()
ourOperationCompletionBlock.name = "Hello짭짭"
ourOperationCompletionBlock.completionBlock = {
    print("Finished on Thread : \(Thread.current)")
}
ourOperationCompletionBlock.addExecutionBlock {
    for i in 0 ... 10 {print("Hello \(i)")}
}
ourOperationCompletionBlock.addExecutionBlock {
    for i in 0 ... 10 {print("짭짭 \(i)")}
}

DispatchQueue.global(qos: .background).async {
    print("Running on Thread : \(Thread.current)")
    ourOperationCompletionBlock.start()
}
print("This will called now \(Thread.current) \(Thread.isMainThread)")

 

** DispatchQueue없이 BlockOperaton을 비동기적으로 작업하게 하기 **

//BlockOperation을 비동기적으로 작업하기 위해서는
//아래 처럼 Thread를 새롭게 생성한 다음 해주면 된다.
let operation = BlockOperation {
    for i in 0 ... 5 {
        print("hello \(i)")
        print(Unmanaged.passUnretained(Thread.current).toOpaque())
        print(Thread.isMainThread)
    }
}

let thread = Thread(block: {
    operation.start()
})
thread.start()

print("Thraed Start")

 

** 비동기적으로 수행 - Operation으로 나만의 구조화된 Task를 생성하자 ** 

//MyOperation을 만들고
//main을 overrid하면
//동기적으로 Operation을 하는 객체를 만들 수 있다.
//그리고 start를 통해 수행시킨다.
class MyOpertaion : Operation {

    override func main() {
        for i in 0 ... 10 {
            print("hello \(i)")
            print(Unmanaged.passUnretained(Thread.current).toOpaque())
            print(Thread.isMainThread)
        }
    }
}

let operation = MyOpertaion()
operation.start()

print("Operation Start")

 

** 비동기적으로 수행 - Opeation으로 구조화된 Task를 생성하자 - 2 **

//나만의 Thread를 만들어서
//비동기적으로 작업을 할 수 있다.
//operation cancel을 하면 작업을 멈춘다.
//모든 작업은 start 이후에
//main에서 본격적인 작업을 하게 된다.
class MyConcurrentQueue : Operation {
    
    override func start() {
        if isCancelled {return}
        Thread.init(block: main).start()
    }

    override func main() {
        for i in 0 ... 9000 {
            if isCancelled {break}
            print("hello \(i) isCanclled : \(isCancelled) \n \(Unmanaged.passUnretained(Thread.current).toOpaque()) \n \(Thread.isMainThread)")
        }
    }
}

let operation = MyConcurrentQueue()
operation.start()

for i in 0...100 {
    print("짭짭 \(i)")
    if i == 100 {
        operation.cancel()
    }
}

 

** 비동기적으로 수행 -  OperationQueue로 구조화된 작업을 사용성 높게 만들자 ** 

//Operation Queue를 사용하면
//위에서 한 것 처럼 Thread를 나눠서 비동기작업을 할 필요가 없다.
//addOperation을 해주면 작동한다.
let operationQueue = OperationQueue()

let blockOperatoin1 = BlockOperation(block: {
    for i in 0...10{
        print("Hello \(i) Thread : \(Thread.isMainThread)")
    }
})

let blockOperation2 = BlockOperation(block: {
    for i in 0...10{
        print("짭짭 \(i) Thread : \(Thread.isMainThread)")
    }
})

operationQueue.addOperation(blockOperatoin1)
operationQueue.addOperation(blockOperation2)

for i in 0...10 {
    print("End \(i) Thread : \(Thread.isMainThread)")
}

 

** 비동기적으로 수행 - OpeartionQueue를 순차적으로 수행하게 하자 ** 

//OperationQueue를 Serial 하게 작업하고 싶을 때
let operationQueue = OperationQueue()

let blockOperatoin1 = BlockOperation(block: {
    for i in 0...10{
        print("Hello \(i) Thread : \(Thread.isMainThread)")
    }
})

let blockOperation2 = BlockOperation(block: {
    for i in 0...10{
        print("짭짭 \(i) Thread : \(Thread.isMainThread)")
    }
})

//maxConcurrentOperationCount의 숫자를 1로 해준다.
//The maximum number of queued operations that can execute at the same time.
//The default value is -1 which means let the system decide
operationQueue.maxConcurrentOperationCount = 1
operationQueue.addOperation(blockOperatoin1)
operationQueue.addOperation(blockOperation2)
for i in 0...10 {
    print("End \(i) Thread : \(Thread.isMainThread)")
}

 

** Opeation의 순서를 정해주자 ** 

//각각의 Operation에 Dependency를 걸어서
//해당 작업이 끝나고 나서 Operation을 수행하게 만들 수 있다.
let operationQueue = OperationQueue()

let blockOperation1 = BlockOperation(block: {
    for i in 0...10{
        print("Hello \(i) Thread : \(Thread.isMainThread)")
    }
})

let blockOperation2 = BlockOperation(block: {
    for i in 0...10{
        print("짭짭 \(i) Thread : \(Thread.isMainThread)")
    }
})

let blockOperation3 = BlockOperation(block: {
    for i in 0...10{
        print("End \(i) Thread : \(Thread.isMainThread)")
    }
})

//맥스를 두개를 주더라도 순서를 맞추게 된다.
operationQueue.maxConcurrentOperationCount = 2
blockOperation1.addDependency(blockOperation2)
blockOperation3.addDependency(blockOperation1)
operationQueue.addOperation(blockOperation1)
operationQueue.addOperation(blockOperation2)
operationQueue.addOperation(blockOperation3)

 

** OperationQueue로 DispatchGroup을 만들어 보자 ** 

//Dependency를 통해서 DispatchGroup을 직접 구현 할 수 있다.
let operationQueue = OperationQueue()

let helloblockOperation = BlockOperation {
    for i in  0...10 {
        print("Hello \(i)")
    }
}

let endBlockOperation = BlockOperation {
    for i in 0...10 {
        print("End \(i)")
    }
}

let worldBlockOperation = BlockOperation{
    for i in 0...10{
        print("World \(i)")
    }
}

//모든 작업이 완료가 되고 나서 불릴 작업
let completeBlockOperation = BlockOperation{
    print("All Operation is Compelted")
}

operationQueue.maxConcurrentOperationCount = 4
completeBlockOperation.addDependency(helloblockOperation)
completeBlockOperation.addDependency(worldBlockOperation)
completeBlockOperation.addDependency(endBlockOperation)

//waitUntilFinished -> False = Main Task와 비동기적으로 작업한다.
//waitUntilFinished -> true = 해당 작업이 모두 끝나고 나서 Main Task를 작업 하도록 한다.
operationQueue.addOperations([helloblockOperation,worldBlockOperation,endBlockOperation,completeBlockOperation], waitUntilFinished: false)

for i in 0...10{
    print("Main Thread is Worked \(i)")
}

 

** OperationQueue로 DispatchGroup을 만들어 보자2 ** 

//waitUntilFinished만들 통해서 dependency 추가 없이 DispatchGroup을 사용할 수 있다.
DispatchQueue.global().async {
    let operationQueue = OperationQueue()

    let helloblockOperation = BlockOperation {
        for i in  0...10 {
            print("Hello \(i)")
        }
    }

    let endBlockOperation = BlockOperation {
        for i in 0...10 {
            print("End \(i)")
        }
    }

    let worldBlockOperation = BlockOperation{
        for i in 0...10{
            print("World \(i)")
        }
    }

    operationQueue.maxConcurrentOperationCount = 4
    operationQueue.addOperations([helloblockOperation,worldBlockOperation,endBlockOperation], waitUntilFinished: true)

    print("All Task Finished Dispatch Group same")
}

for i in 0...50{
    print("Main Thread is Worked \(i)")
}

 

참고사이트 : 

https://zeddios.tistory.com/510

 

iOS ) Concurrency Programming Guide - Operation Queues

안녕하세요 :) Zedd입니다. 흠..저는 Operation Queue는 한번도 사용해본적이 없긴 한데요.. Operation Queues Cocoa operations은 비동기적으로 수행하려는 작업(work)을 캡슐화하는 객체지향적인 방법(object-or..

zeddios.tistory.com

https://ios-development.tistory.com/799

 

[iOS - swift] Operation, OperationQueue, 동시성

Operation single task에 관한 데이터와 코드를 나타내는 추상 클래스 해당 클래스를 서브클래싱하여 사용하면 안정적으로 task를 실행시킬 수 있는 효과 존재 OperationQueue Operation 객체들을 priority에 의.

ios-development.tistory.com

https://ali-akhtar.medium.com/concurrency-in-swift-operations-and-operation-queue-part-3-a108fbe27d61

 

Concurrency in Swift (Operations and Operation Queue Part 3)

This is the continuation of the concurrency in swift series. See part1 and part 2 to understand the basics

ali-akhtar.medium.com

 

728x90
반응형

댓글