728x90
비동기 VS 동기
- 메인 쓰레드가 큐에 작업을 보내고 나서 어떻게 작업을 처리할게 될까?
- 신경 끄고 자기에게 쌓여 있는 다음 일을 한다.
- 보낸 작업이 끝날 때까지 기다린 후에 다음 일을 한다.
- 이 두가지 반응이 비동기와 동기의 개념이다.
- 자기에게 쌓여 있는 다음 일을 실행한다 = 다음 코드 라인을 실행한다.
비동기 (Async)
- 메인 쓰레드가 Queue에 일부 작업을 보내고 난 뒤, 보낸 작업에 대해 신경을 끄고 다음 작업을 실행하는 것을 의미한다.
- Queue에 보낸 작업에 대해서는 더 이상 신경을 쓰지 않고 다음 일을 하는 것이다.
- 보낸 작업에 걸렸을 시간만큼 다른 일을 할 수 있다.
DispatchQueue.global().async {
//task
}
- DispatchQueue: iOS에서 동시성 프로그래밍을 돕기 위해 제공하는 queue
- global: DispatchQueue의 종류
- async: 비동기
→ global dispatch queue에 비동기로 Task를 보낸다.
- 비동기로 보낸다?
- 원래의 작업이 진행되고 있던 메인 쓰레드에서 global dispatch queue로 task를 보낸 후, 해당 작업이 끝나기를 기다리지 않고 이어서 할 일을 하는 것을 말한다.
- 메인 쓰레드에서 실행하는데 걸리는 시간?
- 얼마인지 정확하게 알 수는 없어도 1+2+3인 6초보다는 적게 걸린다는 것을 알 수 있다.
- 왜냐하면, 메인 쓰레드에서는 작업을 queue에 넘기고 나면 더 이상 해당 작업에 대해서는 신경을 쓰지 않고 남아 있는 자기 할 일을 하기 때문이다.
- 일을 Queue에 보내기만 하고 신경을 쓰지 않는다면, 실제 해당 작업이 언제 끝나는지 어떻게 아는가?
- Swift에서는 클로저를 통해서 해당 시점을 알려준다.
- completionHandler, completion이라고 부른다.
동기 (Sync)
- 어떤 작업을 queue에 보낸 뒤 신경 끄고 다음 라인을 실행하는 async와 다르게 queue에 작업을 보낸 작업이 완료 될 때까지 기다린 후에 다음 라인을 실행한다.
- 큐로 보낸 작업이 끝난 후에야 다음 task를 실행하기 때문에 시간 절약이 되지 않는다.
DispatchQueue.global().sync {
//task
}
- 위의 코드를 해석하자면,
- 원래의 작업이 진행되고 있던 메인 쓰레드에서
- global dispatch queue로 task를 보낸 후,
- 다음 라인 실행을 위해 해당 작업이 끝나기를 기다리는 것을 의미한다.
- 메인 쓰레드에서 걸리는 시간?
- 6초보다는 좀 더 걸리겠다고 예상할 수 있다.
- 메인 쓰레드에서는 작업을 queue에 넘긴 후에 해당 작업이 끝나고 나서야 다시 자기 할 일을 하기 때문이다.
- 그렇기 때문에 동기적으로 보내는 코드를 짜게 되면, 실질적으로 메인 쓰레드에서 일을 하게 된다.
왜 비동기 처리가 필요한가?
- 비동기로 처리했을 때 좋은 점은 시간 절약이다.
- 시간이 많이 드는 작업의 대부분은 서버 통신이기 때문에, 네트워크와 관련된 작업들은 내부적으로 비동기적으로 구현이 되어 있다.
큐의 특성 (직렬 VS 동시)
- queue.async { task } 또는 queue.sync { task } 를 통해 task를 queue로 보낸다.
- 그러면, 큐에 쌓여 있는 task들을 다른 쓰레드로 보내야 한다.
- 이 때, GCD/Operation은 다음 두가지 방법으로 보낼 수 있다.
- 한 개의 쓰레드에 몰아 넣는다.
- 여러 개의 쓰레드에 나눠서 넣는다.
→ 둘 중 어떤 방식을 선택할건지가 바로 큐의 특성에 따라서 결정이 된다.
직렬 (Serial)
- (보통 메인 쓰레드에서) 분산 처리 시킨 작업을 다른 한 개의 쓰레드에서 처리하는 큐
동시 (Concurrent)
- (보통 메인 쓰레드에서) 분산 처리 시킨 작업을 다른 여러 개의 쓰레드에서 처리하는 큐
- 몇개의 쓰레드로 분산할 지는 시스템이 알아서 결정한다.
어떤 큐를 사용할 것인가?
- 언제 직렬 큐를 사용하고 언제 동시 큐를 사용할까? 분산처리하는거라면 동시 큐가 좋지 않을까? 라고 생각할 수 있다.
- 어떤 큐를 사용할 것인지에 대한 핵심 포인트는 작업 순서의 중요도에 있다.
- 직렬 큐에 담긴 작업들은 오직 하나의 쓰레드에만 분배된다.
- 모든 작업들이 그 전 작업이 끝나길 기다렸다가 하나씩 실행되기 때문에 task의 시작과 종료에 대한 순서 예측이 가능하다.
- 동시 큐에 담긴 작업들은 여러 개의 쓰레드로 분배된다.
- 선입 선출이라는 큐의 특성상 작업들이 들어온 순서대로 분배되어서 실행은 되지만, 끝나는 순서는 알 수 없다.
- 예를 들어 각 셀에서 이미지를 로드해야 한다고 할 때, 어떤 데이터가 먼저 들어와야 할 지 순서는 중요하지 않다. 그저 빠르면 좋은 것이다. 이런 상황에서는 동시 큐를 사용해야 한다.
- 하지만 반대로 순서가 중요한 작업들을 처리해야 한다면 늦게 들어온 것이 먼저 끝나는 상황을 방지하기 위해 직렬 큐를 써야 한다.
async vs sync
작업을 보내는 시점에서 기다릴지 말지에 대해 다루는 것 것
concurrent vs serial
Queue(대기열)로 보내진 작업들을 여러 개의 쓰레드로 보낼 것인지 한 개의 쓰레드로 보낼 것인지에 대해 다루는 것
- SerialQueue.sync :
- 메인 스레드의 작업 흐름이 queue에 넘긴 태스크가 끝날때까지 멈춰있고(sync), 넘겨진 task는 queue에 먼저 담겨있던 작업들과 같은 스레드에 보내지기 때문에 해당 작업들이 모두 끝나야 실행 (Serial Queue)
- ConcurrentQueue.sync :
- 메인 스레드의 작업 흐름이 queue에 넘긴 태스크가 끝날때까지 멈춰있고(sync), 넘겨진 task는 queue에 먼저 담겨있던 작업들과 다른 스레드에 보내질 수 있기 때문에 해당 작업들이 모두 끝나지 않아도 실행 (Concurrent Queue)
- SerialQueue.async :
- 메인 스레드의 작업 흐름이 태스크를 queue에 넘기자마자 반환되고 (async), 넘겨진 task는 queue에 먼저 담겨있던 작업들과 같은 스레드에 보내지기 때문에 해당 작업들이 모두 끝나야 실행 (Serial Queue)
- ConcurrentQueue.async :
- 메인 스레드의 작업 흐름이 태스크를 queue에 넘기자마자 반환되고 (async), 넘겨진 task는 queue에 먼저 담겨있던 작업들과 다른 스레드에 보내질 수 있기 때문에 해당 작업들이 모두 끝나지 않아도 실행 (Concurrent Queue)
'iOS' 카테고리의 다른 글
[동시성 프로그래밍] GCD - 작업을 큐로 보낸다. / GCD vs Operation (0) | 2023.02.19 |
---|---|
[iOS] Unsplash Search photos (feat.MVVM, Rx, CollectionViewAPI) + 코드 수정 (0) | 2022.10.25 |
[iOS] MVVM+DiffableDataSource+CompositionalLayout (1) | 2022.10.24 |
[iOS] Collection View APIs (0) | 2022.10.23 |
[Realm] Migration (실습) (0) | 2022.10.13 |