오늘은 GCD(Grand Central Dispatch) 에 대해서 정리해보려고 합니다. 예전 게시글 https://norang0.tistory.com/8 에서 해당 개념을 살펴봤을때는 DispatchQueue 를 기차 선로에 빗대서 각각의 작업흐름을 생각해봤는데, 이번에는 비유보다는 동작 자체의 흐름을 다시 그려보려고 합니다.
구체적으로는 DispatchQueue.main 과 DispatchQueue.global(), 그리고 sync 와 async 의 조합을 살펴보려고 합니다. 글자 그대로의 의미부터 살펴보자면 아래처럼 이해하면 될 것 같습니다.
DispatchQueue.main : 메인 스레드에 디스패치 DispatchQueue.global() : 글로벌 스레드* 에 디스패치 |
sync : 동기, 직렬 async : 비동기, 병렬 |
* 구분상 global thread 이라고 표현했지만, 실질적으로는 main thread 이외의 thread 들이라고 생각하면 좋을듯 합니다.
각 용법을 조합하면 아래와 같은 해석(?)이 될 것 같습니다.
DispatchQueue.main.sync | (태스크를) 메인 스레드(Serial)에 동기로 디스패치하겠다 |
DispatchQueue.main.async | (태스크를) 메인 스레드(Serial)에 비동기로 디스패치하겠다 |
DispatchQueue.global().sync | (태스크를) 메인 이외의 스레드(Concurrent)에 동기로 디스패치하겠다 |
DispatchQueue.global().async | (태스크를) 메인 이외의 스레드(Concurrent)에 비동기로 디스패치하겠다 |
알록달록하긴 한데,, 이렇게 적어놓기만 해서는 이해가 쉽게 되지 않아서 그림으로 그려보려고 합니다. 먼저 작업대기열을 그려보겠습니다. 메인에 태스크를 5개 정도 주겠습니다.
DispatchQueue.main.sync | (태스크를) 메인 스레드에 동기로 디스패치하겠다 |
1. 코드의 태스크 2개를 디스패치 구문에 넣었다고 해보겠습니다. 메인스레드에게 동기로 디스패치.
2. 메인스레드는 Dispatch 된 Task 1 과 Task 2 가 끝나길 기다리고 있습니다. 동기처리되어 있기 때문에 다시 움직이려면 1,2 가 끝나야 하거든요.
3. 그런데 Task 1 과 Task 2 가 다시 메인스레드에게 돌아옵니다. 메인스레드는 이 태스크들이 완료되어야 움직일 수 있어서 또 기다립니다.
4. 그렇게 아무도 처리하지 않는 Task 1, Task 2 가 남고... 앱은 무한 대기 상태에 빠지고 DeadLock 이 발생할 수 있습니다.
DispatchQueue.main.async | (태스크를) 메인 스레드에 비동기로 디스패치하겠다 |
1. 이번에는 비동기로 디스패치 하겠습니다. 메인 스레드는 해당 태스크가 끝나길 기다리지 않아도 됩니다. 그래서 Task 3 부터 처리합니다.
2. 비동기로 디스패치 된 태스크들은 메인 스레드의 큐에 추가됩니다.
3. 메인스레드는 가지고 있던 태스크들을 모두 처리하고 할당되어 있는 Task 1, Task 2 도 마저 처리합니다.
DispatchQueue.global().sync | (태스크를) 메인 이외의 스레드에 동기로 디스패치하겠다 |
1. 이번에는 global 을 이용해서 메인 이외의 스레드에게 디스패치 하겠습니다. 하지만 이번에도 동기로 처리되어 메인은 Task 1, Task 2 가 완료될때까지 기다립니다.
2. 메인 이외의 스레드가 해당 Task 1, Task 2 를 처리합니다 (*코드상으로는 그렇지만 실제 메모리 처리로는 메인이 합니다;;)
3. Task 1, Task2 가 끝나고, 메인이 Task 3 부터 다시 작업을 시작합니다.
DispatchQueue.global().async | (태스크를) 메인 이외의 스레드에 비동기로 디스패치하겠다 |
1. global 스레드에게 비동기로 디스패치 합니다. 메인은 Task 1, Task 2 종료까지 기다리지 않아도 됩니다.
2. 메인스레드와 global 스레드가 각자의 일을 갖고 동시에 일을 합니다. 드디어 동시성을 활용할 수 있는 방안이네요.
DispatchQueue 활용에는 여러 옵션이 있고 방법들이 있지만 가장 기본적인 조합은 위 네가지가 아닐까 생각해봅니다. 그런데 그 중에도 sync 는 딱히 쓸 일이 없을 것 같고.... main.async 로 메인스레드의 작업 순서를 조절하거나, global().async 로 네트워크 처리 등 긴 시간이 소요될 것 같은 태스크를 메인에서 덜어내어 병렬처리 하는 정도로 사용할 수 있을 것 같네요. 추후 네트워크를 이용한 기능을 구현하는데에 활용해보면 좋겠습니다!
저한테도 스레드가 한 대여섯개 달려있어서 여러가지 일을 병렬적으로 처리하고 싶다는 생각을 하며 (헤르미온느??) 글을 마무리해봅니다. 그럼 안녕!
'기초탄탄 > Swift' 카테고리의 다른 글
클래스와 구조체, 아직도 난 잘 알지 못한다. (2) | 2025.01.15 |
---|---|
연산프로퍼티 와 UserDefault 로 간편한 CRUD (0) | 2025.01.02 |
생성자(Initializer) : 슈붕으로 드릴까요 팥붕으로 드릴까요 (1) | 2024.11.14 |
Class 와 Protocol 그리고 Extension (feat.UIKit) (0) | 2024.10.28 |