동시성 프로그래밍이 필요한 이유
네트워크 통신과 비동기 처리
네트워크 통신, 서버에 데이터를 요청하는 일은 부하가 많이 걸리는 일이다.
당근마켓의 화면엔 사진과, 정보를 담고 있으며, 이를 스크롤하며 다른 정보들을 갖고있을 수 있다.
비동기 처리를 하지 않으면 한 번에 한 개의 작업만 할 수 있다. 첫번째 사진을 다운로드 -> 첫 번째 정보를 다운로드 -> 두 번째 사진을 다운로드...
그러므로 비동기 처리를 하지않으면 테이블 뷰를 스크롤 할 때 마다 버벅거릴것이다.
아이폰의 메인쓰레드
아이폰의 화면 주사율은 60Hz이다. 1초에 60번 화면을 다시 그린다는 뜻이다. 계산을 해보면 0.01666초에 한 번 화면을 다시 그려야 하며 화면을 다시 그리는 일은 메인쓰레드가한다.
즉 메인쓰레드는 0.01666초를 주기로 한번 화면을 그리게 되는데, 우리가 만약에 0.01666초 보다 더 걸리는 일을 메인쓰레드에 주게된다면 그 일이 끝날 때까지 화면을 다시 그리지 못하고, 일이 다 끝난 후 돌아오는 주기에 화면을 다시 그리게된다.
이를 사용자가 보면 "앱이 버벅거린다" 라고 느끼게 될 것이다.
메인 쓰레드에서 실행이되어 화면이 다시 그려지지 못하는 일이 발생할 수 없도록 *오래걸리는일은 메인 쓰레드가 아닌 서브쓰레드에서 작업을 시킨다.
우리가 작성하는 코드들은 대부분 메인쓰레드에서 실행된다. 그리고 다른 쓰레드를 지정해줄 수 있다.
메인 쓰레드의 오래걸릴 일을 여러 쓰레드에 나누어 분산처리를 하고, 분산처리된 일들의 종료를 메인쓰레드가 기다리지 않도록 비동기처리를 해야한다.
*오래걸리는일: ex) 네트워크작업
💥 iOS에서의 동시성
작업(Task)을 "대기행렬(Queue)"에 보내기만 하면 iOS(운영체제)가 여러쓰레드로 나눠서 분산처리를 한다.
이때 항상 선입선출(FIFO)로 동작한다.
그래서 개발자는 작업(Task)을 "큐(Queue)로 보내기만 하면 된다.
💥 GCD/Operation
위에서 말한 Queue로 Task들을 보내는 방법이다.
iOS 개발에서 주로 사용되고 있는 동시성 프로그래밍 API 2가지로 GCD, Operation가 있다.
- 직접적으로 쓰레드를 관리하지 않고, "큐(Queue, 대기행렬)"라는 개념을 이용해 작업을 분산처리
❓GCD(Grand Central Dispatch)
- Dispatch Queue 사용
- Low level API로 스레드 풀을 관리하며, dispatch queue에 있는 작업들을 사용 가능한 스레드에 스케쥴링한다.
- 개발자는 스레드 관리에 신경쓰지 않아도 되면 Task들을 Dispatch Queue에 넣어주기만 하면 된다.
- 간단한 일, 함수를 사용하는 작업(메서드 위주)에서 사용한다.
//"큐로보낼꺼야","큐의 종류","비동기적으로"
DispatchQueue.global().async{
//다른 쓰레드로 보낼 작업을 배치
//이 클로저 하나가 작업의 뭉탱이
}
❓Operatioin
- Operation Queue사용
- GCD를 기반으로 생성
Operation: GCD + 여러가지 기능(작업 취소. 순서지정, 의존성등)
- 복잡한 일
- 재사용성: 데이터와 기능을 캡슐화한 객체
- 작업 단위 혹은 작업을 래핑하고 나중에 실행할 수 있으며 해당 작업 단위를 여러번 제출 가능.
💥동시(Concurrent)/병렬(Parallel)
❓동시(Concurrent)
실제 1개의 쓰레드(물리적)가 OS영역에서 여러개의 쓰레드로 나뉠 수 있다. 나뉘어진 여러개의 쓰레드(소프트웨어적)는 앱 단위에서 각기 다른 역할로 쓰일 수 있다. 나뉘어질 수 있는 이유는 CPU의 연산속도는 매우 빠르기 때문에 여러가지 작업을 Switching해가며 실행한다 해도 동시에 하는것처럼 보일것이다.
실제 1개의 물리적쓰레드가 여러개의 소프트웨어적 쓰레드로 나뉘어 여러가지의 작업을 처리하는것 = 동시!
❓병렬(Parallel)
실제로 물리적인 쓰레드가 여러개가 있고 여러개의 쓰레드가 각자의 작업을 하는것 = 병렬!