-
[Swift] - Swift์ Task, @MainActor, Task.detached ์ ๋ฆฌ: ์ธ์ , ์, ์ด๋ป๊ฒ ์จ์ผ ํ ๊น?iOS/SWIFT 2025. 5. 3. 11:55728x90๋ฐ์ํ
๐ ๋ชฉ์ฐจ
- ๊ฐ์
- @MainActor๋?
- Task {} vs Task.detached {} ์ฐจ์ด
- ๋ฉ๋ชจ๋ฆฌ์ CPU ๊ด์ ์ฐจ์ด
- ๋ณ๋ ฌ ์์ ์ทจ์ & ์๋ฃ ๊ฐ์ง (withTaskGroup)
- ์ ๋ฆฌ
1. ๊ฐ์
Swift์ Concurrency๋ async/await, Task, Actor ๋ฑ์ ํตํด ์์ ํ๊ณ ํจ์จ์ ์ธ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ์ ๊ณตํ๋ค.
ํ์ง๋ง Task {}, Task.detached {}, ๊ทธ๋ฆฌ๊ณ @MainActor ์ฌ์ด์ ์ฐจ์ด์ ๊ณผ ์ฌ์ฉ๋ฒ์ ์ ํํ ์ดํดํด์ผ ์ ๋๋ก ํ์ฉํ ์ ์์ต๋ค.
์ด ํฌ์คํธ์์๋ ์ด ์ธ ๊ฐ์ง๋ฅผ ์ค์ฌ์ผ๋ก, ์ค์ ๋์ ์๋ฆฌ, ๋ฉ๋ชจ๋ฆฌ/CPU ๊ด์ ์ฑ๋ฅ ์ฐจ์ด,
๊ทธ๋ฆฌ๊ณ TaskGroup์ ํตํ ์ทจ์ ๋ฐ ์๋ฃ ๊ฐ์ง ๋ฐฉ๋ฒ๊น์ง ์ ๋ฆฌํ ๊ฒ์ด๋ค.
2. @MainActor๋?
@MainActor๋ ํน์ ํจ์, ์์ฑ, ํด๋์ค๊ฐ ํญ์ ๋ฉ์ธ ์ค๋ ๋์์ ์คํ๋์ด์ผ ํจ์ ๋ณด์ฅํ๋ ์์ฑ์ด๋ค.
@MainActor class MyViewModel { func updateUI() { // ๋ฌด์กฐ๊ฑด main thread์์ ์คํ } }ํน์ง
- UI ๊ด๋ จ ์์ ์์ ํ์
- await์ ํตํด ๋ค๋ฅธ actor context์์ ์์ ํ๊ฒ ์ ๊ทผ ๊ฐ๋ฅ
- ๋ฐํ์์์ ๊ฐ์ ์ฒดํฌ๋๋ฉฐ, ์๋ฐ ์ ํฌ๋์ ๋ฐ์ ๊ฐ๋ฅ
3. Task {} vs Task.detached {} ์ฐจ์ด์
GCD์์ mainQueue๋ฅผ ์ฌ์ฉํ ์ง operationQueue๋ฅผ ์ฌ์ฉํ ์ง ์ ํ๋ ๊ฒ๊ณผ ๊ฐ์ ๋๋์ด๋ค.
ํญ๋ชฉ Task {} Task.detached {} Actor context ์์ โ ์ ์งํจ โ ์์ ์ฐ์ ์์ ์์ โ ๋จ โ ์ ๋จ (๊ธฐ๋ณธ๊ฐ ์ฌ์ฉ) ๋ฉ์ธ ์ค๋ ๋์์ ์คํ ๊ฐ๋ฅ โ (@MainActor ์์ ์) โ ๋ฌด์กฐ๊ฑด background ๋น๋๊ธฐ ํจ์ ํธ์ถ ๊ฐ๋ฅ โ โ ์บก์ฒ ํ์ฉ (self, viewModel) โ โ (Sendable ์๊ตฌ) // โ ์์ : context ์์๋จ Task { await viewModel.loadData() } // โ ์ค๋ฅ: context ์์, Sendable ์๋ Task.detached { await viewModel.loadData() // ์ปดํ์ผ ์๋ฌ }์ด๊ฒ ์ ์๋ฌ๋๋ฉด viewModel์ ์ด Task๋ฅผ ์คํ์ํค๋ ์์ ํด๋์ค์์ ์์ฑํ์ ๊ฒ์ด๋ค. ํ์ง๋ง Task.detached๋ ์์ context์ ์ ํ ๋ค๋ฅธ ๊ณณ์์ ๋์ํ๊ณ ์๊ธฐ ๋๋ฌธ์ ์ธ๋ถ์ ํ๋กํผํฐ์ ์ ๊ทผํ ์ ์๋ค. ์ค์ฝํ๋ง ์์ ์์ ๋ฟ์ด์ง ๋์ ์๋ก์๊ฒ ์ ํ ์ํฅ์ ์ฃผ์ง ๋ชปํ๋ค๋ ๊ฒ์ด๋ค. ์ํฅ์ ์ฃผ๊ฒํ๋ ค๋ฉด ์๋ก๊ฐ์ ์ด๋ฒคํธ๋ฅผ ์ ๋ฌํ๋ ๋ธ๋ฆฟ์ง ์ญํ ์ด ํ์ํ๋ค.
4. ๋ฉ๋ชจ๋ฆฌ & CPU ๊ด์ ์ฐจ์ด
ํญ๋ชฉ Task {} Task.detached {} Actor/Context ๋ฉ๋ชจ๋ฆฌ ๋ถ๋ชจ context ๊ณต์ ์์ ๋ ๋ฆฝ ARC ์ค๋ฒํค๋ ๋ฎ์ ๋ ํผ (context ๋ณต์ฌ ํ์) ์ค๋ ๋ ๋ถ๋ชจ ์ค๋ ๋ ์ด์ด๋ฐ์ GCD ๊ธ๋ก๋ฒ ํ์์ ์๋ก์ด ์ค๋ ๋ ์ฌ์ฉ ๋ฉ์ธ ์ค๋ ๋ ์ ๊ทผ ๊ฐ๋ฅ (@MainActor ์) ๋ถ๊ฐ๋ฅ (์ง์ Dispatch ํ์) โ ์์ฝ: Task.detached๋ GCD์ DispatchQueue.global().async์ ์ ์ฌํ๊ฒ ๋์ํ์ง๋ง, Swift Concurrency ์์คํ ๋ด์์ ๋์๊ฐ๋ฏ๋ก ์ทจ์, ์ฐ์ ์์ ๋ฑ ๋ ๋ง์ ๊ธฐ๋ฅ์ ์ง์ํจ.
5. ๋ณ๋ ฌ ์์ ์ฒ๋ฆฌ: ํ๋ ์คํจ ์ ์ ์ฒด ์ทจ์ + ์๋ฃ ๊ฐ์ง
๋ณต์์ ๋น๋๊ธฐ ์์ ์ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌํ๊ณ , ํ๋๋ผ๋ ์คํจํ๋ฉด ์ ๋ถ ์ทจ์ํ๊ณ ์ถ๋ค๋ฉด withThrowingTaskGroup์ ์ฌ์ฉํ๋ฉด ๋๋ค.
Task.detached { do { try await withThrowingTaskGroup(of: String.self) { group in group.addTask { try await fetchA() } group.addTask { try await fetchB() } group.addTask { try await fetchC() } for try await result in group { print("โ ์์ ์๋ฃ: \(result)") } print("๐ ๋ชจ๋ ์์ ์ฑ๊ณต") } } catch { print("โ ํ๋ ์ด์ ์คํจ → ์ ์ฒด ์ทจ์๋จ: \(error)") } }โ ํต์ฌ ์์
๊ธฐ๋ฅ ์ฌ์ฉ๋ฒ ๋น๋๊ธฐ ์์ ๋ณ๋ ฌ ์คํ group.addTask ๋ฐ๋ณต ํ๋ ์คํจ ์ ์ ์ฒด ์ค๋จ withThrowingTaskGroup ๊ฐ๋ณ ์๋ฃ ์ถ์ for try await result in group ๋ชจ๋ ์๋ฃ ๊ฐ์ง for ๋ฃจํ ์ข ๋ฃ ์์
6. ์ ๋ฆฌ
์ํฉ ์ถ์ฒ ๋ฐฉ๋ฒ์ด์ UI์์ async ํธ์ถ @MainActor + Task {} ๋ฉ์ธ ์ค๋ ๋ ๋ณด์ฅ ๋ฐฑ๊ทธ๋ผ์ด๋ ๋ ๋ฆฝ ์คํ Task.detached {} ๋ณ๋ ฌ ๋ ๋ฆฝ ์คํ ๋ค์ค ๋น๋๊ธฐ & ์๋ฃ ์ถ์ withTaskGroup or withThrowingTaskGroup ์ทจ์ ๋ฐ ์๋ฃ ์ถ์ ๊ฐ๋ฅ DispatchQueue.global ๋์ฒด Task.detached {} Swift Concurrency ๊ธฐ๋ฐ, await ์ฌ์ฉ ๊ฐ๋ฅ
๐ง ๋ง๋ฌด๋ฆฌ
- Task {}๋ context-aware, actor-safeํ ๋น๋๊ธฐ ์คํ์ ์ํด ์ฌ์ฉ
- Task.detached {}๋ ๋ ๋ฆฝ์ ์ธ ๋ณ๋ ฌ ์คํ์ ์ํ ์ ์์ค ๋๊ตฌ์ด๋ฉฐ, ์ฃผ์ ๊น๊ฒ ์ฌ์ฉํด์ผ ํจ
- ๋ณต์กํ ๋น๋๊ธฐ ํ๋ฆ ์ ์ด์๋ TaskGroup์ด ํต์ฌ์ด๋ฉฐ, ๊ตฌ์กฐํ๋ concurrency ์ค๊ณ์ ํ์
'iOS > SWIFT' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Swift] - Swift์์ ํด๋์ค ๋ด๋ถ ๊ตฌ์กฐ์ฒด์ ๋ฉ๋ชจ๋ฆฌ ์์น์ ์ฑ๋ฅ ์ฐจ์ด (1) 2025.05.03 [Swift] - ๋ฐฐ์ด ๋ฃจํ๋ฅผ ์ํํ๋ ๋ฐฉ์(enumerated,indices,Range(0..<arr.count)) (0) 2025.03.20 [Swift] - Character์ EGC(Extended Grapheme Cluster) (0) 2025.03.14 [Swift] - mutating (0) 2024.02.06 [SWIFT] - ์ ๋ค๋ฆญ(Generic) (0) 2023.06.14