Skip to content

Commit a22048e

Browse files
committed
Add Swift Concurrency
1 parent 7e8fcaa commit a22048e

File tree

2 files changed

+164
-0
lines changed

2 files changed

+164
-0
lines changed
Lines changed: 4 additions & 0 deletions
Loading
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
---
2+
title: Swift Concurrency
3+
date: 2026-02-06 21:24
4+
tags: Swift, Concurrency
5+
image: thumbnail/swift-concurrency.svg
6+
description: Swift Concurrency에 대해서 알아보겠습니다.
7+
---
8+
9+
### Swift Concurrency란
10+
11+
Swift 5.5에서 나온 Swift Concurrency는 단순하게 `DispatchQueue`를 대체 하는것이 아닌 다양한 문제를 해결해 주는 강력한 도구이다.
12+
13+
- 비동기 로직이 늘어날 때 completion handler 지옥 발생
14+
- 상태 기반 아키텍처 등에서 비동기 이벤트 스트림 처리의 복잡도 증가
15+
16+
### DispatchQueue, Swift Concurrency 비교
17+
18+
일단 먼저 DispatchQueue의 본질은
19+
20+
DispatchQueue는 아래 책임을 가진다.
21+
- 작업(Block)을 queue에 넣는다
22+
- 스레드 풀에 작업을 분배
23+
- 직렬 / 병렬 실행을 보장한다
24+
25+
```swift
26+
DispatchQueue.global().async { ... }
27+
```
28+
29+
위 코드에서 GCD는 언젠가 실행되는것과, 현재 스레드 블로킹 하지 않음을 보장한다.
30+
그리고 이 작업의 소유자, 취소 가능 여부, 다른 작업과의 관계, 데이터 레이스 방지, 상태 일관성 등은 보장하지 않는다.
31+
32+
즉 DispatchQueue는 실행기(executor)이지, 동시성 모델이 아니다.
33+
34+
#### DispatchQueue기반 동시성의 한계
35+
36+
```swift
37+
var count = 0
38+
39+
DispatchQueue.global().async {
40+
count += 1
41+
}
42+
```
43+
44+
이 코드는 컴파일이 성공 하고, 런타임 겅공이 가능하며, 결과는 비결정적이며 데이터레이스는 전적으로 개발자의 책임이다.
45+
46+
```swift
47+
let queue = DispatchQueue(label: "counter")
48+
49+
queue.async {
50+
count += 1
51+
}
52+
```
53+
54+
해결하기 위해서 위 코드 처럼 작성하면, 결국 설계 부담이 전부 개발자에게 오게 된다.
55+
56+
### Swift Concurrency의 핵심 철학
57+
58+
1. Structed Concurrency
59+
2. Cooperative Thread Pool (Swift Runtime)
60+
3. Date Race를 컴파일 타임에 차단하는 시도
61+
62+
```swift
63+
async let a = fetchA()
64+
async let b = fetchB()
65+
let result = await a + b
66+
```
67+
68+
이런 식으로 사용하게 되면 이러한 장점을 챙길 수 있다.
69+
70+
- `a`, `b`의 부모 스코프에 생명주기가 종속됨
71+
- 부모 Task 가 cancel 되면 자식 Task 도 함께 cancel 됨
72+
- Task Tree가 명확해져서 디버깅 및 추론이 쉬워짐
73+
74+
75+
Swift Concurrency로 이렇게 작성하면
76+
77+
```swift
78+
Task {
79+
await doWork()
80+
}
81+
```
82+
83+
이러한 단계를 거친다.
84+
85+
1. Task 객체 생성
86+
2. 부모 Task 에 구조적으로 연결
87+
3. 취소 전파 경로 확보
88+
4. 실행은 Executor에 위임
89+
5. Actor isolation 검사
90+
91+
즉 Swift Concurrency는 실행을 직접하는것이 아닌, 실행은 `Executor`가 하고 그 밑에 GCD 가 존재한다.
92+
93+
### Swift Concurrency 동작
94+
#### Executor
95+
- Swift Concurrency의 실행 단위
96+
- Task를 실제 스레드에 매핑
97+
- 대표적인 Executor
98+
- MainActor executor -> main thread
99+
- Global executor -> cooperative thread pool
100+
101+
#### 내부 구조
102+
- Global executor은 libdispatch(GCD) 위에서 동작
103+
- cooperative scheduling (thread 점유 최소화)
104+
105+
> Swift Concurrency → Executor → GCD → Kernel Thread
106+
107+
방식으로 구동되며, DispatchQueue가 대체 된다고 보다는 밑으로 내려간게 맞다.
108+
109+
### 예제
110+
#### DispatchQueue
111+
```swift
112+
func loadUser(completion: @escaping (User) -> Void) {
113+
DispatchQueue.global().async {
114+
let user = fetchUser()
115+
DispatchQueue.main.async {
116+
completion(user)
117+
}
118+
}
119+
}
120+
```
121+
122+
#### Swift Concurrency
123+
```swift
124+
func loadUser() async throws -> User {
125+
try await fetchUser()
126+
}
127+
```
128+
129+
DispatchQueue랑 Swift Concurrency는 표현력부터 다르다.
130+
131+
현재 위 두개의 예시를 비교 하면, DispatchQueue는 흐름이 분산되고, 에러 전달도 복잡하고, 취소가 불가능하며 테스트의 어려움을 겪을수 있다.
132+
133+
하지만 Swift Concurrency를 사용한 곳에서는, 동기 코드 처럼 가독성이 올라갔고, 에러 전파가 자동으로 되며, Task cancel이 가능하고 테스트가 용이 하다는 장점이 있다.
134+
135+
136+
### 구조적 동시성 vs 비구조적 동시성
137+
138+
DispatchQueue
139+
- 작업간 관계 없음
140+
- fire-and-forget
141+
- 추적 불가
142+
143+
Swift Concurrency
144+
- 부모-자식 Task 트리
145+
- 취소 / 에러 전파
146+
- 생명주기 명확
147+
148+
### 결론
149+
150+
DispatchQueue를 써야 할 때
151+
- C / legacy API 래핑
152+
- barrier, concurrent queue 제어
153+
- low-level synchronization
154+
- 성능 실험
155+
156+
Swift Concurrency를 써야 할 때
157+
- 앱 레벨 비동기 로직
158+
- 네트워크 / IO
159+
- 상태 기반 아키텍처
160+
- 테스트 가능한 코드

0 commit comments

Comments
 (0)