안녕하세요! 피피아노입니다🎵
이번 포스팅에서는 동시성(Concurrency) 개념에 대해서 정리를 해보려고 합니다.
동시성(Concurrency)
Swift는 비동기(Asynchronous)와 병렬(Parallel) 코드를 구조적으로 작성할 수 있는 강력한 기능을 제공합니다. 이 기능들을 통해 앱의 성능을 최적화하고, 사용자 경험을 향상시킬 수 있습니다.
비동기 코드(Asynchronous Code)
비동기 코드는 일시적으로 중단되었다가 다시 실행될 수 있는 코드를 의미합니다. 프로그램의 한 부분만 실행되지만, 실행을 중단하고 다시 시작함으로써 긴 작업(예: 네트워크 요청, 파일 분석)을 수행하는 동안 짧은 작업(예: UI 업데이트)을 계속 진행할 수 있습니다. 이렇게 하면 앱이 사용자에게 더 부드럽고 반응성이 좋은 경험을 제공할 수 있습니다.
병렬 코드(Parallel Code)
병렬 코드는 동시에 여러 부분의 코드가 실행되는 것을 의미합니다. 예를 들어, 이미지 처리 작업이 여러 개 있을 때, 이를 병렬로 실행하면 각각의 작업이 독립적으로 동시에 처리될 수 있습니다. 이렇게 하면 작업 시간이 크게 단축됩니다.
동시성의 장점과 고려사항
동시성과 비동기 코드를 사용하면 여러 작업을 동시에 수행할 수 있어 앱의 효율성을 높일 수 있습니다. 하지만 이러한 유연성에는 복잡성이 증가하는 비용도 수반됩니다. Swift는 동시성 코드를 작성할 때 컴파일 시간에 문제를 찾아주는 등의 검사를 통해 이러한 복잡성을 줄여줍니다.
예를 들어, Swift의 실행자(executor)를 사용하면 변경 가능한 상태에 안전하게 접근할 수 있습니다. 그러나 동시성을 추가한다고 해서 항상 코드가 빠르거나 오류가 없다는 보장은 없습니다. 오히려 동시성 코드를 잘못 작성하면 디버깅이 어려워질 수 있습니다.
비동기 함수 정의와 호출(Defining and Calling Asynchronous Functions)
비동기 함수는 실행 중에 일시 중단될 수 있는 특수한 함수입니다. 이러한 함수는 다른 동기 함수와는 다르게, 실행 도중 무언가를 기다릴 수 있습니다. Swift에서는 async 키워드를 사용하여 비동기 함수를 정의하고 호출할 때는 await 키워드를 사용합니다. 비동기 함수는 네트워킹, 파일 입출력 등 시간이 오래 걸릴 수 있는 작업을 수행할 때 유용합니다.
비동기 함수 정의
비동기 함수를 정의하려면 함수 선언에 async 키워드를 추가합니다. 함수가 값을 반환한다면 async를 반환 타입 앞에 작성합니다.
func listPhotos(inGallery name: String) async -> [String] {
// 비동기 네트워킹 코드
let result = // ... some asynchronous networking code ...
return result
}
만약 함수가 에러를 던질 수 있다면 throws 키워드 앞에 async를 추가합니다.
func listPhotos(inGallery name: String) async throws -> [String] {
// 비동기 네트워킹 코드
let result = // ... some asynchronous networking code ...
return result
}
비동기 함수 호출
비동기 함수를 호출할 때는 await 키워드를 사용합니다. await는 함수가 반환될 때까지 실행을 일시 중단합니다.
let photoNames = await listPhotos(inGallery: "Summer Vacation")
let sortedNames = photoNames.sorted()
let name = sortedNames[0]
let photo = await downloadPhoto(named: name)
show(photo)
- 코드는 첫번째 줄에서 실행을 시작하고 첫번째 await 까지 실행됩니다. listPhotos(inGallery:) 함수를 호출하고 해당 함수가 반환될 때까지 실행을 일시 중단합니다.
- 이 코드의 실행이 일시 중단되는 동안 같은 프로그램의 다른 동시 코드가 실행됩니다. 예를 들어 오랜시간 실행되는 백그라운드 작업이 새 사진의 리스트를 업데이트 할 수 있습니다. 이 코드는 await 로 표시된 다음 중단 지점 또는 완료될 때까지 실행됩니다.
- listPhotos(inGallery:) 가 반환된 후에 이 코드는 해당 지점에서 시작하여 계속 실행됩니다. 반환된 값을 photoNames 에 할당합니다.
- sortedNames 와 name 을 정의하는 라인은 일반적인 동기 코드 입니다. 이 라인은 await 로 표시되지 않았으므로 가능한 중단 지점이 없습니다.
- 다음 await 는 downloadPhoto(named:) 함수에 대한 호출을 표시합니다. 이 코드는 해당 함수가 반환될 때까지 실행을 다시 일시 중단하여 다른 동시 코드에 실행할 기회를 제공합니다.
- downloadPhoto(named:) 가 반환된 후에 반환값은 photo 에 할당된 다음에 show(_:) 를 호출할 때 인수로 전달됩니다.
새로 배우게 된 부분
- Swift의 비동기 코드: Swift는 async와 await 키워드를 사용해 비동기 코드를 작성하여 네트워크 요청이나 파일 입출력과 같은 시간이 오래 걸리는 작업을 효율적으로 처리할 수 있게 합니다.
- 병렬 처리의 이점: 병렬 코드를 통해 여러 작업을 동시에 실행함으로써 CPU 자원을 최대한 활용하고, 특히 데이터 처리나 이미지 처리와 같은 작업에서 성능을 크게 향상시킬 수 있습니다.
- 동시성과 복잡성: 동시성과 비동기 코드를 사용하면 애플리케이션의 응답성을 높일 수 있지만, 코드의 복잡성이 증가하며 잘못된 구현은 디버깅을 어렵게 만들 수 있습니다. Swift는 컴파일 시간 검사를 통해 이러한 복잡성을 줄이는 데 도움을 줍니다.
- 실행자(Executors): Swift의 실행자는 비동기 코드에서 안전하게 상태를 변경할 수 있도록 설계되어, 데이터 레이스와 같은 동시성 문제를 예방하는 데 중요한 역할을 합니다.
- 비동기 함수 정의: async 키워드를 사용하여 비동기 함수를 정의할 수 있으며, 함수가 에러를 던질 수 있는 경우에는 async 키워드를 throws 앞에 추가하여 선언합니다.
- 비동기 함수 호출: 비동기 함수를 호출할 때 await 키워드를 사용하여 해당 함수의 완료를 기다릴 수 있으며, 이는 코드의 동기적 흐름을 유지하면서 비동기 작업을 수행할 수 있게 합니다.
- 비동기 네트워킹: 비동기 함수는 특히 네트워킹 작업에서 유용하며, await 키워드를 통해 네트워크 응답을 기다리는 동안 UI 업데이트와 같은 다른 작업을 계속 진행할 수 있습니다.
- 데드락 방지: Swift의 동시성 모델은 비동기 작업 간의 교착 상태를 방지하도록 설계되어, 안전하고 효율적인 비동기 프로그래밍을 지원합니다.
- 쓰레드 양보(yielding the thread): await는 비동기 함수나 메서드가 완료되기를 기다리는 동안 코드 실행을 일시 중단합니다. Swift가 현재 쓰레드에서 코드의 실행을 일시 중단하고 다른 코드를 실행할 수 있게 하여 쓰레드 양보라고도 부릅니다.
내용이 길어져서 다음 포스팅에서 이어서 더 정리해보겠습니다!
참고: https://bbiguduk.gitbook.io/swift/language-guide-1/concurrency
감사합니다.
잘못된 내용이 있거나 더 좋은 내용 피드백은 언제나 환영합니다!
궁금하신 부분은 댓글로 질문 부탁드립니다!
'Apple > Swift' 카테고리의 다른 글
[Swift] URL 살펴보기 (0) | 2024.08.07 |
---|---|
[Swift] 동시성(Concurrency) 톺아보기 (2/2) (2) | 2024.07.25 |
[Swift] 고차함수(Higher-order function) 이해하기 (2) | 2024.06.27 |
[Swift] Implicitly Unwrapped Optional (암묵적 옵셔널 추출)과 Optional Chaining (옵셔널 체이닝) (0) | 2024.04.11 |
[Swift] 배열(Array) (0) | 2024.03.13 |