Swift Concurrency(1), (2)에서는 기본적인 async-await 동작과 continuation에 대해 다뤄 보았음.
이번 글은 Swift Concurrency의 동작원리에 대해 알아보고자 하며 WWDC 영상을 정리한 글임.
아래 영상을 보거나 글을 먼저 읽고 이 글을 읽는 것을 추천함.
(WWDC 21) Swift concurrency: Behind the scenes
Swift Concurrency(1) - Async와 Await
Swift Concurrency(2) - Continutation
GCD와 스레드 익스플로전
GCD를 사용할 때 어떤 문제가 발생할 수 있을지 먼저 살펴보겠음.
네트워킹을 통해서 여러 주제의 뉴스 피드를 가져오고 이를 데이터베이스에 순차적으로 저장하는 앱을 만든다고 가정함.
일반적으로 생각해보면 네트워크 요청을 동시에 처리해서 병렬성을 활용할 수 있고 메인스레드를 차단하지 않으며 진행됨.
근데 진짜로 문제가 없을까 생각해보면 성능적인 함정이 존재함.
우리는 병렬큐를 사용하고 있는데 병렬큐는 여러 쓰레드에게 일을 동시에 시키고 있음.
근데 네트워킹 작업이 끝나고 데이터베이스를 갱신할 때 동기적으로 처리하고 있기 때문에 중단지점이 발생한다는 것임.
GCD는 이 중단시점에 새로운 스레드를 생성해서 네트워킹 대기열의 작업들을 계속 이어나가게 함.
이는 동시성 수준을 높이기 위함이지만 스레드 간 컨택스트 스위칭이 빈번하게 발생하며 오버헤드가 커지게 됨.
이런 현상을 스레드 익스플로전⭐️이라고 함. (사실 Concurrency의 핵심이라고 봐도 무방하다..)
Swift Concurrency
Swift Concurrency에서는 스레드 간의 컨택스트 스위칭 대신 Continuation 이라는 경량 개체가 존재함.
이전 포스팅에서 함수의 진행상황을 추적할 수 있게 해준다고 언급했었는데 이 경량개체는 함수 호출 정도의 비용만 지불하고 작업 전환을 할 수 있다고 함.
Swift Concurrency에서 추구하는 바는 아래와 같음!
1. 스레드를 차단하는 것이 아닌 함수의 일시정지(= 스레드 제어권을 시스템에게 주고 다른 작업을 할 수 있게) 해주고 싶음.
2. CPU의 물리코어만큼 스레드의 생성이 되고, 효율적으로 항목 간 전환이 되는 것임.
Async Fucntions (그래서 어떻게 스레드를 포기할 수 있을까!?)
실행중인 프로그램의 모든 스레드에는 함수 호출에 대한 상태를 저장하는 스택이 존재함.
스레드가 함수를 호출하면, 새 프레임이 스택에 푸시되고 이 스택 프레임은 일시 중단 지점에서 사용할 필요 없는 지역변수, 반환주소 등의 정보를 가짐. 또한 대기 전과 후에 사용되어야 하는 변수(예를 들어 newArticles 변수) 는 비동기 프레임에 저장됨.
이렇게 상태를 저장하고 있기 때문에, 스레드를 포기하고 돌아왔을 때도 다시 실행을 이어나갈 수 있게 됨.
Adoption of Swift Concurrency
마구잡이로 Concurrency를 도입하지 않는 것이 좋다.
Concurrency를 도입하는 데에는 동시성과 관련된 일부 비용이 발생하게 되기 때문에 실질적으로 이점이 될 경우에만 사용하도록 해야함.
단순히 UserDefaults값을 읽는데 동시성을 도입하는 것은 이점이 없을 수 있음.
대기 전과 후의 스레드는 동일한가?
동일할수도 동일하지 않을 수도 있음. 동일 스레드를 보장하지 않음.
await은 작업이 자발적으로 취소될 수 있기 때문에 원자성이 깨졌음을 나타내는 명시적 지점임.
Actor
위의 예제에서 데이터베이스 갱신과 네트워킹을 하는 부분을 Actor로 바꾼다면 효율적인 스케줄링을 할 수 있음.
그래서 액터가 뭘까?
액터는 한번에 하나의 Task만 접근할 수 있도록 하여 데이터 레이스(경쟁상태)를 방지해줌.
또한 접근이 직렬화되어 있어 여러 스레드에서 동시에 실행되지 않도록 함.
Actor hopping
액터 호핑은 한 액터에서 다른 액터로의 실행 전환을 하는 과정을 말함.
스포츠 피드 액터에서 데이터베이스 액터로 전환할 때 스포츠 피드 액터는 일시중단되며 스레드를 차단하지 않음.
또한 액터 호핑은 다른 스레드를 필요로 하지 않음.
만약 날씨 피드 액터가 데이터베이스를 갱신해야할 때 스포츠 피드 데이터베이스 저장이 끝나지 않았다면 대기열이 생기고 날씨 피드 액터는 일시중단됨. 여기서 D1의 실행이 완료되면 보류중인 D2나 피드 액터나 다른 작업이 수행될 수 있음.
Actor reentrancy & reprioritization
액터 재진입과 우선순위 재조정을 통해 우선순위 역전문제의 해결이 가능해짐.
데이터베이스 액터에 보류중인 작업이 있더라도 D2를 수행하기 위해 데이터베이스 액터에 재진입할 수 있음.
이는 액터가 엄격하게 선입선출으로 항목을 실행할 수 있음을 의미하며, 액터 재진입을 위해 우선순위가 높은 항목을 낮은 항목보다 대기열 앞쪽으로 이동할 수 있음.
'iOS > iOS 지식' 카테고리의 다른 글
[iOS] Fastlane + Github Action으로 CI/CD 구축하기(2) - Fastlane Match를 활용한 인증서 관리 및 Github Action 연동 (0) | 2025.03.13 |
---|---|
[iOS] Fastlane + Github Action으로 CI/CD 구축하기(1) - Fastlane을 통한 TestFlight 업로드 (2) | 2025.03.13 |
[iOS] Keychain으로 민감정보 저장하기 (2) | 2025.02.25 |
[iOS] StackView의 Distribution과 Alignment (0) | 2024.11.28 |
Swift Concurrency(2) - Continutation (0) | 2024.11.11 |