Xcode/Swift - PlayGround

PlayGround) Opeation Queue - 1

후르륵짭짭 2022. 1. 17. 23:02
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
반응형