ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Swift] - Swift์˜ Task, @MainActor, Task.detached ์ •๋ฆฌ: ์–ธ์ œ, ์™œ, ์–ด๋–ป๊ฒŒ ์จ์•ผ ํ• ๊นŒ?
    iOS/SWIFT 2025. 5. 3. 11:55
    728x90
    ๋ฐ˜์‘ํ˜•

     

    ๐Ÿ“š ๋ชฉ์ฐจ

     

    1. ๊ฐœ์š”
    2. @MainActor๋ž€?
    3. Task {} vs Task.detached {} ์ฐจ์ด
    4. ๋ฉ”๋ชจ๋ฆฌ์™€ CPU ๊ด€์  ์ฐจ์ด
    5. ๋ณ‘๋ ฌ ์ž‘์—… ์ทจ์†Œ & ์™„๋ฃŒ ๊ฐ์ง€ (withTaskGroup)
    6. ์ •๋ฆฌ

    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 ์„ค๊ณ„์— ํ•„์ˆ˜
Designed by Tistory.