굿데이 여러분 오랜만입니다
오늘은 Dispatch Queue 에 대해서 간단하게 정리해보려구 합니다
Dispatch Queue 는 Serial Queue 와 Concurrent Queue 가 있는데여
Serial Queue 는 말그대로 직렬로 해당 Queue 에 여러 작업이 있으면 먼저 실행된 작업이 종료될때까지 다른 작업들은 대기를 타는 친구구여
Concurrent Queue 는 병렬 Queue 이기 땜시 Serial 과는 달리 Queue 안에 들어가 있는 친구들이 '동시에' 작업을 합니다 물론 순서는 먼저온 친구가 먼저 시작하긴 하는데, 누가 먼저 끝날지는 몰라여 ㅎ;
일단 여기서 1차 정리
시리얼큐 -> 먼저 들어온 놈이 혼자 먼저 실행되고, 이게 끝나야 다음 놈이 실행될수있음
컨커런트큐 -> 먼저들어온 놈이 먼저 실행은 되는데, 다음 놈들도 뒤따라서 바로바로 실행됨, 동시에 작업이 실행되기 땜시 누가 먼저 끝날지 몰라!
참 쉽져?
이제 서위퍼터에서 제공해주는 기본적인 큐를 알아보면, 저희가 맨날 UI 조작할때 쓰는거 하나 있쥬?
바로 DispatchQueue.main 입니다. 이친구는 바로 시리얼큐에여
그리고 DispatchQueue.global() 이 있는데 ,이 친구는 컨커런트큐입니당
근데 main 같은 경우는 따로 줘야할 값이 없는데, global 같은 경우는 뒤에 뭔가를 넣을 수가 있잖아여?
바로 그것이 qos 인데, Quality of Service 로 해당 큐의 중요도를 지정해주는 겁니다
기본은 default 이기 때문에 저희가 따로 뭐 안주고 global() 로 해도 잘 돌아가기는 합니다..
이 친구들은 enum 으로 구성되어 있어서 해당 큐의 중요도에 따라 지정해주면 되는데,
간단하게 보면 UI 나 즉각적으로 반응해야 하는 부분이 윗부분이구,
네트워크 작업과 같이 백그라운드에서 돌아야 하는 작업들은 background 로 지정해주면 된다고 편하게 생각하시면 될듯 합니당
그리고 이 두가지 제공해주는 큐 말고 저희가 직접 만들수도 있는데염
let customQueue = DispatchQueue(label: "custom") // Serial Queue
let customConcurrentQueue = DispatchQueue(label: "concurrent", attributes: .concurrent) // Concurrent Queue
label 과 attributes 를 지정해주면 아주 간단하게 커스텀 큐를 만들 수 있게 됨미다
자 이제 sync 와 async 에 대해서 알아보게씀니다
sync 는 큐 내부에서 해당 작업이 완료 될때까지 '기다리는' 것이고,
async 는 해당 작업과 동시에 다른 작업들도 '함께' 처리가 되는 것이라고 생각하시면 맘이 편합니당
시리얼큐와 컨커런트큐에서 이 두 친구들이 어떻게 작동되는지 알아보게씀니다.
먼저 컨커런트부터 알아볼게여 with global 큐큐
DispatchQueue.global().sync {
for i in 0...5 {
print(i, "%")
}
print("VVVVVVVVVV")
}
DispatchQueue.global().sync {
for i in 6...10 {
print(i, "$")
}
print("QQQQQQQQQQ")
}
for i in 11...15 {
print(i, "^")
}
print("XXXXXXX")
자 이렇게 되면 0...5의 작업이 먼저 실행되고 끝날때까지 암것도 못합니다.
그 다음 큐에 들어가있는 6...10 이 출력이 되고 난 후에야 큐 안에 들어가있지 않은 친구 11...15 가 출력이 되겠죵?
하지만 global queue 를 async 로 하게 되면?
아주 난리가 납니다. 순서고 뭐고 없이 출력이 되는데여 바로 async 하게 queue 안의 작업이 끝나지 않아도 다른 작업을 실행하기 때문입니다.
자 그러면 이제 serial queue 를 테스트해봅시당
이번엔 async 부터 해볼께여
let queue = DispatchQueue(label: "custom")
queue.async {
for i in 0...50 {
print(i, "%")
}
print("VVVVVVVVVV")
}
queue.async {
for i in 51...100 {
print(i, "$")
}
print("QQQQQQQQQQ")
}
for i in 101...150 {
print(i, "^")
}
print("XXXXXXX")
커스텀 시리얼큐를 만들고 돌리면,
101...150 은 async 이기 때문에 호출되는 순서를 알순 없게 됩니다.
하지만 저희가 확신할 수 있는건? 시리얼큐 안에 들어가 있는 0...50 과 51...100 은 첫번째 작업이 끝나야만 출력이 된다는 점이져
sync 는 뭐 똑같습니다 queue 안에 있는 두 작업들이 완료가 되어야만 101...150 이 출력이 되는 것이져
그런데 왜 저 위에서는 컨커런트 큐 테스트할때 제공해주는 global() 을 썼는데,
시리얼큐 테스트때는 main 을 안쓴것일까 궁금해하시는 분이 혹시 있으실거 같아서 첨언을 드립니다
바로 main 을 sync 로 호출하게 되면 생기는 문제 때문인데여,,
main Queue 를 sync 로 호출하게 되면 아래와같은 오류메시지와 함께 앱이 터지게 됩니다
Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
이는 main Thread 가 Thread-safe 하지 않기 때문이라고,,,합니다,,, 자세한 사항은 아래 제드님의 글이 있으니 참고하시면 될것 같아여
zeddios.tistory.com/519?category=682195
그리고 main queue 의 경우에는 다른 serial queue 와는 달리 async 를 해도 queue 밖에 있는 다른 친구들이 중간에 들어가질 않더라구여
이것도 아마 다른 serial queue 와는 다른 main queue 만의 특성이 아닌가,,,하는 생각을 해봅니다.
지금까지 아주 간단하게 dispatch queue 에 대해서 정리해보았는데여
혹시라도 이상한 부분이 있다면 편하게 지적해주시면 감사하게씀니다
그럼 다음에 또 만나요 안녕~
'Swift 개발 이야기' 카테고리의 다른 글
Content Hugging & Compression Resistance Priority in Swift (0) | 2020.09.22 |
---|---|
CollectionView Carousel Paging in Swift (1) | 2020.09.14 |
XIB 를 이용해서 Custom View 만들기 (0) | 2020.08.04 |
iOS Custom Font 사용하기 (0) | 2020.07.08 |
SwiftUI 의 Navigation 기능 간단하게 써보기 (0) | 2020.06.23 |