일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- Firebase
- Tuist Swift
- 네트워크 통신
- swift
- SeSAC
- realm
- Firebase Analytics
- swift database
- ios swiftdata
- Swift Tuist
- arc
- ios
- Combine
- swift 6
- ribs
- swift 5.9
- observable
- Subscribe
- swift db
- 카카오뱅크 ios
- xcode
- Tuist
- JSON
- GCD
- swiftdata
- Subject
- RxSwift
- ios database
- SwiftUI
- KeyPath
- Today
- Total
천원의 개발
Swift Concurrency(동시성 프로그래밍) 본문
먼저 동시성 프로그래밍이란?
Computer Science에서는 특정 프로세스의 실행 시간이 다른 프로세스의 흐름과 겹치는 상황에서 동시에 실행한다고 말합니다.
위의 사진을 보시면 Thread A와 B가 Concurrent하게 동작하는 모습입니다. 반면에 B와 C는 개별적으로 동작하는 모습을 확인 할 수 있습니다. A와 B처럼 ContextSwitching을 통하여 스레드의 흐름이 겹치도록 수행하는 것을 동시성이라 말합니다.
Swift 5.5 이전의 동시성
Swift 5.5에서 새로운 동시성 모델을 제시하기 전까지는 저희는 GCD와 CompletionHandler를 사용해 비동기 프로그래밍을 작성해왔습니다. GCD API로 비동기 작업을 처리하고, CompletionHandler로 비동기가 끝나는 시점에 필요한 작업을 수행하였습니다.
위의 코드는 채용프로세스에 관혀여 비동기 코드를 GCD와 CompletionHandler를 사용하여 작성한 코드입니다. 서류시험, 코딩테스트, 1차 면접, 라이브코딩 순으로 코드가 동작하는 모습입니다.
기존 코드의 문제점
가장 큰 문제로는 가독성을 말할 수 있을 것 같습니다. 기존의 CompletionHandler를 이용하여 코드를 작성하게 되면 너무 많은 CallBack이 발생하게 되고 그로 인해 점점 들여쓰기가 많아지면서 가독성이 저하되는 모습을 확인할 수 있습니다. 또한 모든 case에서 CompletionHandler를 사용하여 error처리를 해주어야 하며, 순환 참조의 발생 또한 개발자가 개발시에 고려해야 하는 부분입니다.
Async-Await
이런 부분들을 개선하고자 Swift 5.5 이후에 나온 것이 async-await 문법입니다.
Async 키워드를 통하여 비동기 함수임을 나타내고, Await 키워드를 통하여 메서드의 리턴을 기다려 순차적으로 실행할 수 있습니다. Completion Handler가 사라지면서, 비동기 함수를 한 줄로 처리할 수 있어서 훨씬 간결해진 모습입니다. 덕분에 가독성적인 측면에서 많이 개선이 되었으며 동시에 순환참조 문제 또한 해결된 모습입니다. try await 키워드를 빼먹을 경우 컴파일 시점에서 오류가 발생하기 때문에 개발자 입장에서는 조금 더 안정적으로 에러 핸들링이 가능해진 모습입니다.
Thread
스레드 측면에서 GCD를 보면 개발자는 너무 많은 스레드가 생기지 않도록 제어하거나, 세마포어를 사용해 할당되는 스레드의 수를 제한하는 방법을 사용해야 했습니다. 그렇지 않아서 Thread Explosion이 발생하게 된다면 빈번한 컨텍스트 스위칭으로 인한 성능저하와 DeadLock등의 문제를 마주하게 될 것입니다.
WWDC 2021에 따르면, 애플은 스레드 관리를 개발자에게 맡기기보단 시스템 자체에서 처리해 안전성을 보장하고자 하였습니다. 그래서 시스템이 넘겨 받은 작업의 우선순위와 실행하기 적절한 스레드를 고려하여 제어권을 넘겨줍니다.
Suspend와 Resume의 과정을 보면 await 키워드를 만나면 Suspension point로 지정 후 일시 정지하고 스레드의 제어권을 시스템에게 넘겨줍니다. task가 재개되는 시점에서 시스템이 다시 적절한 스레드로 제어권을 넘겨주어 task가 재개되게 됩니다. 이렇게 되면 함수가 일시정지 되는 과정에서 추가적인 스레드의 생성 없이 적절한 스레드로 task가 배정되게 됩니다. 그렇다면 왜 추가적인 스레드의 생성 없이 실행할 수 있을까요? 다음으로 한번 알아보겠습니다.
Continuation
기존의 동시성 프로그래밍을 구현하기 위해서는 여러개의 스레드를 사용해 처리해야 했습니다. 이처럼 여러개의 스레드 작업을 번갈아가며 처리할 때 컨텍스트 스위칭이 발생합니다. 그러나 새로운 Swift 동시성 모델에서는 각 task에 대해서 스레드를 생성하는 대신 Countination을 할당합니다. 여기서 Countination이란 특정 지점에서 함수 실행 Context를 추적할 수 있는 객체입니다. 아래에서 이미지와 함께 조금 더 설명하겠습니다.
Swift Concurrency에서는 비동기 함수의 실행을 Stack과 Heap에서 관리를 합니다. Heap 영역에는 Suspension point에서 실행하는데 필요한 함수들을 저장합니다. 이것을 Continuation이라고 부르며, 이를 통해 일시정지된 함수의 상태를 추적해 어디서부터 재개할지 알 수 있습니다. 만약 live coding이 재개가 된다면 stack최상단 frame이 live coding으로 교체가 됩니다. 작업의 교체만이 이루어진다면 새로 스레드를 생성하는 것이 아닌 기존의 스레드를 재사용하는 것이 가능하여 시스템에서 적절한 스레드를 배치하는 방식으로 동작하는 것입니다. 이러한 과정은 Context Switching 없이 함수 호출 만으로도 작업의 변경이 가능해 스케줄링 오버헤드를 줄일 수 있는 이점이 있습니다.
'iOS&Swift🍎 > Swift' 카테고리의 다른 글
Swift RIBs (0) | 2023.07.27 |
---|---|
Swift 전처리문 (#if Debug #endif) (0) | 2023.05.16 |
Swift 메모리 구조 정리 (0) | 2023.01.12 |
Swift Closure Capturing Values, 클로저 값 캡처 (0) | 2022.09.08 |
Swift GCD(Grand Center Dispatch), DispatchQueue.main.sync 에서 DeadLock이 발생하는 이유 (0) | 2022.09.05 |