iyOmSd/Title: iOS Think🤔

[iOS] Swift Thread - Dispatch Queue, Operation Queue

냄수 2019. 12. 21. 00:44
반응형

[iOS] 회사 면접을 가게 되면 꼭 나오는 필수 질문이기도하고

쓰면서도 헷갈리고 비슷한데 뭐가다르지?? 고민한 적이 있었던 내용이에요

 

간단하게 요약하자면

 

Operation Queue

Concurrent Operation객체를 구현할 필요없이

Operation을 Operation Queue에 제출하기만하면

Concurrent Operation객체를 만들어 줍니다

 

Dispatch Queue

Operation을 하기에는 단순한 코드들 구현할 때 사용

DispatchQueue()처럼

그냥 새로만드는 객체로 만드는 큐는 Serial Queue

Attribute를 줘야 Concurrent로 생성할 수 있어요

 

 

 

 

 

 

쓰레드 개념을 간단하게 설명하자면

Serial vs Concurrent

Serial : 직렬처리

Concurrent : 병렬처리

 

Async vs Sync

Async : 비동기

Sync : 동기

 

로 구분되요

 

Serial인 경우는 직렬이기때문에 앞에 작업이있고 그뒤에 작업이 있다면

앞의 작업이 끝나기전까지는 뒤에작업을 실행 하지않겠죠??

 

반대로 Concurrent인경우는 병렬이기 때문에 여러가지 작업을 동시에 실행 할 수 있어요

조금이라도 먼저온 작업순으로 바로바로 처리해줄 수 있어요

 

Async는 비동기에요!

비동기란 제가 작업을 맡기고 그 실행되는동안에 저는 다른 일을 할 수 있는거에요

예를들어, 커피를 주문하고 저는 기다리는 동안 아무것도 못하는게 아니라 다른일을 할 수 있는 그런 느낌이에요

 

Sync는 반대로 해당 작업이 끝날때까지 기다려야 해요

 

이 개념들을 보면 약간의 혼동이 올 수 있어요...

음..? 왜 같은데 다르지!!?

 

Serial과 Concurrent는 스레드 수와 관련 있는 개념이고

Async와 sync는 스레드 위에서의 흐름을 나타내는 거라고 생각해요

 

그리고 Cocoa Aplication에서는 2개의 Queue를 지원해요

● main
     Serial queue
     ‼️반드시‼️ UI관련 task는 이곳에서 실행

 

● global
     Concurrent queue ( global dispatch queue)
     동시에 하나이상의 task실행
     큐에 추가된 순서대로 시작

 

코드로 한번 비교해볼까요??

 

 

Concurrent sync

DispatchQueue.global().sync {
   for i in 1...5 {
       print(i)
   }
   print("==================")
}
for i in 10...13 {
	print(i)
}

///////////////////////////////////
              실행결과
///////////////////////////////////

1
2
3
4
5
===============
10
11
12
13

sync의 코드가 끝나야 그 다음코드가 실행 되는것이 보이죠

 

 

Serial sync

위와 마찬가지의 결과가 나와요

 

만약 global이 아닌

main.sync를 하면 에러를 볼 수있을거에요!!

main thread에서는 앱의 작동과 관련된 작업을 하고 있는데 sync을 걸어버리면 끝날때까지

기다리므로 앱이 죽게되죠!!

Concurrent async

global.async {

    for문 🐶

}

 

global.async {

    for문 🐷

}

< Code >

 

=> 🐶🐷🐷🐶🐷🐶🐶🐷

병렬처리이기 때문에 이렇게 막 섞여나오고

비동기 처리이므로 완료여부와 상관없이 다음코드인 도중에 Code부분도 실행되요

 

 

Serial async

queue.async {

    for문 🐶

}

 

queue.async {

    for문 🐷

}

< Code >

 

=> 🐶🐶🐶...🐷🐷🐷...

직렬처리이기 때문에 🐶task가 끝나야만 🐷task가 실행되고

비동기 처리이기 때문에 기다리지않고 도중에 Code부분이 실행되요

 

 

Qos (Quality of Service)

쓰레드를 다루다 보면 Qos라는 단어를 한번쯤 본적이 있을거에요

 

qos란!!


쓰레드의 중요도를 표시하고
앱이 수행하는 작업에 적합한 qos클래스를 지정하면 앱이 반응적이고 에너지 효율이 좋다는것을 보장가능

 

Qos에는 여러 Level이 있는데요


● User-interactive
    ○ main thread에서 작업, UI새로고침, 애니메이션등 사용자와 상호작용하는 작업
     반응성과 성능을 중점에둠
     순식간에 끝남

 

● User-initated
     사용자가 시작한 작업, 즉각적인 결과가 필요
     반응성과 성능에 중점
     순식간 또는 몇초 그이하

 

● Default
     Qos정보가 할당되지않은 작업
     GCD global queue는 이 level에서 실행

 

● Utility
     작업완료하는데 약간의 시간이 걸릴수 있음
     즉각적인 결과 필요없음
     반응,성능,에너지효율성 간에 균형유지 중점
     작업은 몇초에서 몇분정도걸림

 

● Background
     백그라운드에서 작동
     사용자가 볼수 없는 작업
     에너지효율성에 중점
    

사용자의 작업이 발생하지 않는 시간의 90%이상을 Utility Qos Level에서 실행권장하고 있어요

 

 

Dispatch Queue와 Operation Queue의 차이는 뭘까요??

Operation Queue에서
→ 동시에 실행할수있는 연산의 최대수 지정가능

→ Key Value Observing(KVO)를 사용할수있는 많은 프로퍼티들이 있음
→ 일시중지, 다시시작, 취소가능

Operation Queue : 비동기적 실행작업을 객체 지향적인 방법으로 사용하는데 적합
Dispatch Queue : 작업이 복잡하지않고 간단하게 처리하거나 특정유형 시스템이벤트 비동기처리시 적합(ex: 타이머, 프로세스 )

 

 

인스턴스 하나를 Concurrent에서 접근시?

class ins {
    var a = 1
    
    func simpleAdd() {
        self.a += 1
        print("simpleAdd")
    }
    
    func simpleMul() {
        self.a *= 2
        print("simpleMul")
    }
}
let one = ins()
DispatchQueue.global().async {
    for _ in 0..<10 {
        one.simpleAdd()
        print("add: \(one.a)")
    }
}

DispatchQueue.global().async {
    for _ in 0..<10 {
        one.simpleMul()
        print("mul: \(one.a)")
    }
}

 

→ for문 안의 `add, mul`는 순서없이 출력
→ 클래스 메소드에 있는 `simpleAdd, simpleMul`의 출력순서도 순서없이 출력
→ 계산 순서도 랜덤적으로 실행

반응형