Swift Concurrency
WWDC 2021 에서 새로 소개된 동시성 프로그래밍 API.
Swift Concurrency는 동시성 프로그래밍을 가독성이 좋은 깔끔한 코드로 작성하고자 도입된 개념이다.async
와await
키워드를 이용해 비동기 테스크 종료 후 코드를 작성할 수 있다.
await
키워드로 인해 중지되면 이후에 사용해야 하는 데이터를 힙(heap) 영역에 저장해 두고, 이후에 다시 힙 영역에서 해당 데이터를 가져와 사용한다.
Objective-C에서 비동기 작업을 위해 자주 사용하는 GCD(Grand Central Dispatch) 의 단점을 파악해보고,
이를 보완하기 위한 뉴페이스(?) Swift Concurrency와 비교해보자.
에러 처리를 위해 모든 case에서 completion handler 호출이 필요하다. 개발자의 실수로 completion handler 호출을 빠뜨린다면 에러 처리에 누락이 발생한다. 😱
또한, 코드 내부에서 self
키워드에 접근해야 한다면 retain cycle(참조 사이클) 발생 가능성을 고려해야 한다. 그렇다고 무분별한 [weak self]
의 사용은 런타임 오버헤드를 발생시킬 수도 있고, nil을 체크해야 하는 수고를 거쳐야 한다.
✅ Swift Concurrency로 작성하면 에러 핸들링은 throw
로, 데이터 전달은 return
으로 분리할 수 있다. 이런 식으로 작성하면 guard let - else 구문에서 completion handler를 누락하는 실수를 방지할 수 있다.
비동기 작업이 연쇄적으로 일어나는 경우, 코드의 가독성이 떨어진다.
간단한 예제로 비교해보자.
💥 GCD를 이용한 코드
func makeCrunchyCookie(completion: @escaping ((Cookie) -> Void)) {
makeDough { dough in // ✅ (1)
self.chillDough(dough: dough) { ripedDough in // ✅ (2)
self.bakeCookie(dough: ripedDough, time: bakeTime) { cookie in // ✅ (3)
self.drawFace(cookie: cookie) { crunchyCookie in // ✅ (4)
completion(crunchyCookie)
}
}
}
}
}
➡️ 예제에서는 4개의 간단한 로직이라 읽기 어렵지 않지만, 로직이 조금만 복잡해져도 클로저의 늪에 빠지게 된다😵!
💥 Swift Concurrency를 이용한 코드
func makeCrunchyCookie() async throws -> Cookie {
let dough = try await makeDough() // ✅ (1)
let ripedDough = try await chillDough(dough: dough) // ✅ (2)
let cookie = try await bakeCookie(dough: ripedDough, time: bakeTime) // ✅ (3)
let crunchyCookie = try await drawFace(cookie: cookie) // ✅ (4)
return crunchyCookie
}
일반적으로 함수가 호출되면 stack에 push되고, 실행이 끝나 함수가 return 되면 pop을 수행한다. 기존에 동시성 프로그래밍을 구현하기 위해서는 여러 개의 스레드를 사용해 처리해야 했다. 이처럼 여러 개의 스레드 작업을 번갈아가며 처리할 때 컨텍스트 스위칭(context switching)이 발생한다.
컨텍스트 스위칭이 많아지면 성능이 저하될 수 있으며, 블록된 스레드가 어떤 자원을 잠그고(lock) 있을 때 데드락을 발생시킬 수도 있다.
반면, Swift Concurrency에 도입된 코루틴에서는 비동기 함수의 실행을 stack과 heap에서 관리한다. stack에는 비동기 함수를 실행할 때 사용되지 않는 지역변수들을 저장한다. 추가로 heap에는 suspension point
에서 실행하는데 필요한 함수 컨텍스트들을 저장한다. 이것을 continuation
이라고 부르며, 이를 통해 일시정지된 함수의 상태를 추적해 어디서부터 재개할지 알 수 있다.
참조