동기, 비동기
동기(synchronous): 앞선 작업이 끝날 때까지 다른 작업들이 기다리는 것
비동기(asynchronous): 앞선 작업에 상관없이 작업을 시작하는 것
CompletionHandler
작업이 끝난 시점에 수행할 작업으로 비동기 작업에서 작업이 끝나는 시점을 알릴 때 주로 사용
completionHandler 콜백 문제점
- 중첩될 수록 코드의 가독성이 안 좋아진다
- 오류 처리가 어렵고 장황해진다.
- 호출을 잊을 수도 있다.
- self capture + cycle retain 발생 가능
Async & Await
컴플리션 핸들러의 장황한 코드 블록과 복잡한 에러 핸들링 문제를 해결하기 위해 Swift 5.5부터 도입된 개념
비동기 코드를 마치 동기 코드처럼 작성할 수 있게 해 준다.(외관상)
컴플리션 핸들러 코드
func processImageData2c(completionBlock: (Result<Image, Error>) -> Void) {
loadWebResource("dataprofile.txt") { dataResourceResult in
switch dataResourceResult {
case .success(let dataResource):
loadWebResource("imagedata.dat") { imageResourceResult in
switch imageResourceResult {
case .success(let imageResource):
decodeImage(dataResource, imageResource) { imageTmpResult in
switch imageTmpResult {
case .success(let imageTmp):
dewarpAndCleanupImage(imageTmp) { imageResult in
completionBlock(imageResult)
}
case .failure(let error):
completionBlock(.failure(error))
}
}
case .failure(let error):
completionBlock(.failure(error))
}
}
case .failure(let error):
completionBlock(.failure(error))
}
}
}
processImageData2c { result in
switch result {
case .success(let image):
display(image)
case .failure(let error):
display("No image today", error)
}
}
async await 코드
func loadWebResource(_ path: String) async throws -> Resource
func decodeImage(_ r1: Resource, _ r2: Resource) async throws -> Image
func dewarpAndCleanupImage(_ i : Image) async throws -> Image
func processImageData() async throws -> Image {
let dataResource = try await loadWebResource("dataprofile.txt")
let imageResource = try await loadWebResource("imagedata.dat")
let imageTmp = try await decodeImage(dataResource, imageResource)
let imageResult = try await dewarpAndCleanupImage(imageTmp)
return imageResult
}
async
함수 뒤에 async를 통해 비동기라는 걸 명시할 수 있다.
async 코드는 동시 콘텍스트(concurrent context)에서만 실행 가능하다. 즉, 다른 async 함수 내 혹은 Task를 통해 수동으로 동시 콘텍스트를 제공할 때 사용할 수 있다.
await
async 함수를 호출하기 위한 키워드.
await 키워드로 마킹된 곳은 potential suspension point(잠재적인 일시 중단 지점)로 지정된다. 해당 함수가 대기 상태가 되면, caller 역시 대기 상태가 될 수 있다.
suspend
suspend 될 수 있다는 건 스레드가 다른 동작을 수행할 수 있게 제어권을 넘길 수 있다는 것
내부 동작 원리(스레드 관리)
sync
- sync에서의 스레드 관리
- 호출 - A함수에서 B함수(sync)를 호출하면, A함수가 실행되던 스레드의 제어권을 B에게 전달
- 진행 - B함수가 끝날 때까지 해당 스레드는 점유되어서 다른 일을 수행하지 않게 되는 원리
- 종료 - B함수가 종료되면 A함수에게 다시 스레드 제어권을 반납
async
- async에서의 스레드 관리
- 호출 - A함수에서 B함수(async)를 호출하면, A함수가 실행되던 스레드의 제어권을 B에게 전달
- 진행 - B함수는 async이기 때문에 스레드의 제어권을 포기하는 suspend가 가능 (suspend 되면 호출한 A함수도 같이 suspend 됨)
- suspend - 스레드에 대한 제어권은 system으로 가고 시스템은 스레드를 사용하여 다른 작업을 수행
- resume - 일시 중단된 비동기 함수 B를 다시 실행하는 단계
- 종료 - B함수가 종료되면 A함수에게 스레드 제어권을 반납
await으로 표시된 코드의 일시 중단 지점은 같은 이유로 스레드 양보(thread yielding)라고도 불린다.
await 키워드를 통해 코드 블록이 하나의 트랜잭션으로 처리되지 않을 수 있음을 암시한다.
즉, 함수가 정지(suspend)되고, 다른 작업이 먼저 실행될 수 있기 때문에 일시 중단되는 동안 앱의 상태가 크게 변할 수 있다.
직렬, 동시
직렬과 동시는 동기와 비동기와는 다른 개념이다.
직렬, Serial
(보통 메인 스레드에서) 분산 처리 시킨 작업을 “다른 한 개의 스레드에서” 처리하는 큐
동시, Concurrent
(보통 메인 스레드에서) 분산 처리 시킨 작업을 “다른 여러 개의 스레드에서” 처리하는 큐
async vs sync
작업을 보내는 시점에서 기다릴지 말지에 대해 다루는 것
concurrent vs serial
Queue(대기열)로 보내진 작업들을 여러개의 스레드로 보낼 것인지 한 개의 스레드로 보낼 것인지에 대해 다루는 것
스레드, thread
어떠한 프로그램 내에서, 특히 프로세스 내에서 실행되는 흐름의 단위를 말한다.
일반적으로 한 프로그램은 하나의 스레드를 가지고 있지만, 프로그램 환경에 따라 둘 이상의 스레드를 동시에 실행할 수 있다. 이러한 실행 방식을 멀티스레드(multithread)라고 한다.
thread pool
스레드 풀은 동시에 실행되는 작업을 관리하는 데 사용되는 메커니즘
스레드 풀은 작업을 처리하는 쓰레드들의 집합으로 구성되며, 이 쓰레드들은 작업이 도착하면 해당 작업을 실행하고 다음 작업을 기다리는 역할을 한다.
In Swift…
쓰레드 풀
쓰레드 풀은 작업자 스레드의 모임으로 시스템에 의해 생성되고 관리된다.
각 작업에 대해 새 스레드를 만드는 대신 스레드 풀은 기존 스레드를 재사용해 효율성을 향상한다.
대기열, Queue
실행할 작업은 큐에 배치된다.
스레드 풀은 이 큐에서 작업을 가져와 실행 가능한 스레드에 할당한다.
작업자 스레드, Worker Threads
실제 작업을 수행하는 스레드.
스레드 풀에 의해 만들어지고 관리되며 작업자 쓰레드는 큐에서 작업을 수행하고, 실행한 다음 더 많은 작업을 수행할 수 있다.
스위프트 자체는 GCD(Grand Central Dispatch)라는 메커니즘을 포함하는 Dispatch 프레임워크를 통해 동시성으로 작업할 수 있는 방법을 제공한다.
GCD는 쓰레드 관리의 많은 로우 레벨 디테일을 추상화한다.
참고
[iOS - swift] Async, Await 사용 방법
[Swift] async / await & concurrency
'Swift' 카테고리의 다른 글
Swift: Result Builder (0) | 2024.08.13 |
---|---|
Swift: 이벤트 큐, 이벤트 핸들러 (0) | 2024.08.12 |
Swift: OperationQueue (0) | 2024.08.12 |
Swift: XCTest (0) | 2024.08.12 |
Swift: 정규 표현식 (0) | 2024.08.12 |