DispatchQueue 로 Task 를 전달한 Main Thread
GCD 의 Queue 인 Dispatch Queue 에 Task 를 전달한 Main Thread. 이제 Task 1 은 GCD 가 Thread 를 생성하여 Task 1 을 분배한 후, Task 1 이 종료되면 생성한 Thread 를 삭제할 것이다.
그럼 Main Thread 는 남은 Task 2, 3, 4 를 어떻게 처리할까?
두 가지로 나누어 생각해 볼 수 있다.
1. 비동기 (async) : 바로 Task 2 를 받아서 수행한다.
Queue 에 보낸 작업이 끝나는 것을 기다리지 않고 이어서 Task 를 수행하는 것.
앞서 DispatchQueue.global().async 를 설명했었다.
아래와 같이 남은 Task 2, 3, 4 를 async 를 통해 처리한다고 가정해보자.
① Task 2 가 queue 로 들어간다. 이제 GCD 가 알아서 Thread 를 생성하고 Task 2 를 수행한다.
② Task 2 가 끝나는 것을 Main Thread 는 기다리지 않고 바로 Task 3 를 마찬가지로 수행한다.
③ Task 3 가 끝나는 것을 Main Thread 는 기다리지 않고 바로 Task 4 를 수행한다.
아마 모든 작업을 처리하는데 1초가 채 걸리지 않을 것이다.
그렇다면 실제 Task 가 끝나는 것은 어떻게 확인할 수 있을까?
이는 completionHandler or completion 이라는 클로저를 통해 끝나는 해당 시점을 알려준다.
2. 동기 (sync) : Task 1 이 종료될 때까지 기다렸다가 다음 Task 2 를 수행한다.
Queue 에 보낸 작업이 끝나는 것을 기다렸다가 다음 라인을 수행한다.
이번에는 async 가 아니라 DispatchQueue.global().sync 이다.
마찬가지로 아래와 같이 남은 Task 2, 3, 4 를 sync 를 통해 처리한다고 가정해보자.
이때 걸리는 시간은 얼마나 걸릴까?
Task 2 를 globla() Queue 로 보낸 후, Task 2 가 종료되기까지 1초를 기다린 후 Task 3 가 시작된다.
Task 3 을 global() Queue 로 보낸 후, Task 3 가 종료되기 까지 2초를 기다린 후 Task 4 가 시작된다.
Task 4 를 global() Queue 로 보낸 후, 4초 후 Task 4 가 종료된다.
7초 조금 이상 소요될 것이다.
그렇다면 굳이 Task 가 끝나는 것을 기다리는데 왜 Main Thread 가 아닌 GCD 가 새로운 Thread 를 생성하고 Task 를 생성한 Thread 로 보내는 수고를 할까?
그러므로 sync 처리를 하더라도 코드는 실질적으로 Main Thread 에서 실행된다.
왜 비동기 처리가 필요할까?
크게 두가지로 정리할 수 있다.
먼저 시간 절약이다. 위 실습에서도 확인하였듯 Task 를 처리하는데 소요되는 시간이 매우 차이난다.
시간이 많이 드는 작업은 대부분 서버와의 통신이다. 그러므로 네트워크 관련된 Task 는 내부적으로 비동기로 구현되어 있다.
다음은 URLSession 을 활용하여 URL 의 endpoint 로부터 데이터를 다운로드하거나 업로드 하는 작업의 예시이다.
let session = URLSession(configuration: .default)
session.dataTask(with: url) { [weak self] data, response, error in
// Task
}
내부적으로 다른 Thread 를 사용함과 동시에 비동기로 구현되어 있기 때문에, 따로 async 처리를 하지 않아도 된다.
' iOS > 동시성 프로그래밍' 카테고리의 다른 글
동시성 프로그래밍 - Serial(직렬) 과 Concurrent(동시) (1) | 2022.10.01 |
---|---|
동시성 프로그래밍 - GCD 와 Operation (1) | 2022.09.30 |