@@ -7,21 +7,23 @@ description: Actor에 대해서 알아보겠습니다.
77---
88
99### Actor 란
10+
1011` Actor ` 는 Swift Concurrency에서 Data Race를 컴파일 타임에 방지하기 위해 도입된 reference 타입입니다.
1112
1213Actor가 나오기 전엔, class는 여러 스레드에서 동시에 접근할 수 있기 때문에, 개발자가 직접 ` DispatchQueue ` , ` NSLock ` , ` Semaphore ` 등을 통해서 동기화를 보장해야했지만, 그로 인해 유지보수 비용이 매우 높아졌다.
1314
1415하지만 Actor는 이를 언어 차원에서 해결해준다.
1516
16-
1717### Actor의 핵심 보장
18+
1819- 한 시점에 단 하나의 Task만 actor의 mutable state에 접근 가능
1920- 동기화 코드를 직접 작성하지 않아도 됨
2021- 잘못된 동시 접근은 컴파일 에러로 차단
2122
2223즉 Actor는 Thread-safe한 class를 기본값으로 제공한다고 하면 이해하기 쉽다.
2324
2425### Actor의 기본 구조
26+
2527``` swift
2628actor Counter {
2729 var value: Int = 0
@@ -53,9 +55,10 @@ Task {
5355
5456` actor ` 내부의 ` var ` 은 자동으로 보호되며 외부에서 접근시 반드시 ` await ` 가 필요하고, 내부에서는 ` await ` 없이 자기 자신의 state 접근 가능하다.
5557
56-
5758### Actor Isolation
59+
5860Actor에서는 Isolation이 존재한다.
61+
5962- actor의 모든 mutable state는 actor의 executor에 격리되게 된다.
6063- 외부에서는 actor 내부 상태에 직접 접근이 불가하다.
6164
@@ -85,6 +88,7 @@ actor UserStore {
8588
8689await store.add (" Jihoon" )
8790```
91+
8892이 구조 덕분에 데이터 레이스는 구조적으로 불가능합니다.
8993
9094### Actor vs Class + Lock
@@ -103,14 +107,16 @@ final class SafeCounter {
103107 }
104108}
105109```
110+
106111문제점
112+
107113- lock 누락 가능성
108114- 데드락 위험
109115- 가독성 저하
110116- 테스트 난이도 상승
111117
112-
113118Actor 방식을 사용하면
119+
114120``` swift
115121actor SafeCounter {
116122 private var value = 0
@@ -144,6 +150,7 @@ actor Config {
144150- mutable state 접근은 불가
145151
146152### Reentrancy (재진입성)
153+
147154Actor는 reentrant하다.
148155
149156``` swift
@@ -161,14 +168,16 @@ actor BankAccount {
161168
162169문제는, ` await ` 중에 다른 task가 끼어들 수 있고, 논리적 경쟁 상태 (logical race) 발생 가능합니다.
163170이를 해결하려면, 중요한 연산은 ` await ` 없이 한 번에 처리하며, State snapshot 사용하면 된다.
171+
164172``` swift
165173func withdraw (_ amount : Int ) {
166174 guard balance >= amount else { return }
167175 balance -= amount
168176}
169177```
170-
178+
171179### Global Actor (MainActor)
180+
172181``` swift
173182@MainActor
174183class ViewModel {
@@ -179,20 +188,24 @@ class ViewModel {
179188특정 executor(주로 Main Thread)에 격리 시킬수 있습니다.
180189
181190### 성능
191+
182192Actor같은 경우
193+
183194- lock 기반 보다 약간 오버헤드가 존재
184195- context switching 비용
185196- executor enqueue/dequeue
186197
187198하지만
199+
188200- 대부분의 앱에서 체감 불가 수준
189201- lock 사용에 대한 버그 비용보다는 오버헤드가 감수 할 정도
190202
191203Actor를 사용하면 안되는 경우
204+
192205- 초당 수십만번 호출 되는 hot path 경우
193206- 매우 짧은 atomic 연산
194207
195- 대신
208+ 대신
196209` ManagedAtomic ` (Swift Atomics)와 value type + task-local 로 처리 하면 됩니다.
197210
198211### 언제 사용해야되나
@@ -202,8 +215,8 @@ Actor를 사용하면 안되는 경우
202215- Analytics, Logging
203216- ViewModel, Domain Service
204217
205-
206218### 피해야되는 경우
219+
207220- 수치 연산 중심 코드
208221- tight looop
209222- 단일 스레드 보장 환경
0 commit comments