<h1><center> iOS interview 4 </center></h1> ###### tags: `πŸ’» λ©΄μ ‘ 질문` ###### date: `2025-09-2017:21:33.284Z` > [iOS interview](https://github.com/JeaSungLEE/iOSInterviewquestions) # Async-await # Swift Concurrency의 κΈ°λ³Έ λ™μž‘ κ°œλ… > κ·Έ 전에.. Concurrencyλž€? 일반적인 κ°œλ…, λ‹€λ₯Έ μ–Έμ–΄λ‚˜ ν”Œλž«νΌμ—μ„œλ„ ν†΅μš©λ˜λŠ” 일반적인... - 'μ—¬λŸ¬ μž‘μ—…μ„ λ™μ‹œμ— λ‹€λ£¨λŠ” 것' ``` gemini Concurrency (λ™μ‹œμ„±) ν•˜λ‚˜μ˜ CPU μ½”μ–΄κ°€ μ—¬λŸ¬ μž‘μ—…μ„ λ²ˆκ°ˆμ•„ κ°€λ©° μ‹€ν–‰ν•˜λŠ” 방식. => gcd, swift concurrencyλ‚˜ 이걸 μˆ˜ν–‰ν•œλ‹€. 그런데, μž‘λ™ 방식이 λ‹€λ₯΄λ‹€. 예λ₯Ό λ“€μ–΄, μ›Œλ“œ λ¬Έμ„œλ₯Ό μž‘μ„±ν•˜λ©΄μ„œ λ™μ‹œμ— μŒμ•…μ„ λ“£λŠ” 경우, CPUλŠ” μ›Œλ“œ ν”„λ‘œμ„Έμ‹±κ³Ό μŒμ•… μž¬μƒ μž‘μ—…μ„ 맀우 짧은 μ‹œκ°„ λ‹¨μœ„λ‘œ λΉ λ₯΄κ²Œ μ „ν™˜ν•˜λ©° μ‹€ν–‰ν•΄μš”. λ™μ‹œμ— μ§„ν–‰λ˜λŠ” 'κ²ƒμ²˜λŸΌ' λ³΄μ΄λŠ” 것이 ν•΅μ‹¬μ΄μ—μš”. ``` μž‘μ—…μ˜ λ‹¨μœ„λ₯Ό CPUλŠ” ThreadλΌλŠ” κ³΅κ°„μ—μ„œ μ²˜λ¦¬ν•œλ‹€. 1. gcd μ–΄λ–»κ²Œ λ™μž‘ν•˜λ‚˜? - Grand Central Dispatch - GCD -> Async/Await ? Thread Explosion 막기 μœ„ν•¨ why? Context Switching - GCD -> Threadλ₯Ό CPUκ°€ κ°€μƒμœΌλ‘œ μ—¬λŸ¬ 개λ₯Ό λ§Œλ“€ 수 μžˆλ‹€. - λ™μ‹œμ„±μ„ μ œκ³΅ν•˜κΈ° μœ„ν•΄μ„œ - how? μ—¬λŸ¬ μž‘μ—…λ“€μ˜ λ°œμƒμ„ context switching을 μ΄μš©ν•΄μ„œ λ‹€λ₯Έ μ“°λ ˆλ“œλ‘œ λ„˜μ–΄κ°€μ„œ cpuκ°€ μž‘μ—…μ„ ν•œλ‹€. 기쑴에 μž‘μ—… μ€‘μ΄λ˜ μ“°λ ˆλ“œλŠ”? - 문제점: 1. (λ‚΄λΆ€ Threadμ—μ„œ) context switching이 μΌμ–΄λ‚œλ‹€. | 2. κΈ°μ‘΄ μž‘μ—…μ΄λ˜ κ°€μƒμ˜ μ“°λ ˆλ“œλŠ” 계속 λ‚¨μ•„μžˆλ‹€... => μ“°λ ˆλ“œ 폭발 | 3. μš°μ„ μˆœμœ„κ°€ 잘 μ•ˆ μ§€μΌœμ§ 2. swift concurrencyλŠ” μ–΄λ–»κ²Œ λ™μž‘ν•˜λ‚˜? - Swift Concurrency -> CPUλ‹Ή Threadκ°€ ν•˜λ‚˜λ§Œ μ‘΄μž¬ν•©λ‹ˆλ‹€. | **ν˜‘λ ₯적 Thread Pool** <-> **μ„ μ ν˜•(GCD)** μž‘μ—…μ˜ 비동기 μ‹œμ μ΄ λ°œμƒν•˜λ©΄ μ‹œμŠ€ν…œ(OS)에 λ„˜κΈ΄λ‹€. - await ```swift let task = Task { // prevA let a = await fn(); // prevB let b = fn2(); // prevC let c = await fn(); } task.cancel() // => CPU0 - [prevA]await [....] [a prevB b prevC] await [....] [] let queue = DispatchQueue(label: "queue") let a = DispatchWorkItem() let b = DispatchWorkItem() let c = DispatchWorkItem() // => Thread0 [prevA] // => Thread1 ------- [a prevB prevC] // => Thread2 -----------------------[c] | queue.task { } ``` ---- ## Task와 async-await - What is Task? β†’ **`β€œλΉ„λ™κΈ°μ μΈ μž‘μ—… μ‹€ν–‰ λ‹¨μœ„λ₯Ό λ§Œλ“œλŠ” 것”`** - 메타데이터 상속: 이 μž‘μ—…μ΄ μ–΄λŠ μ“°λ ˆλ“œμ—μ„œ λ™μž‘ν•˜λŠ”μ§€, μš°μ„ μˆœμœ„, 둜컬 λ³€μˆ˜ - TaskLocal https://developer.apple.com/documentation/swift/tasklocal ```swift enum Example { @TaskLocal static var traceID: TraceID? } func read() -> String { if let value = Self.traceID { "\(value)" } else { "<no value>" } } await Example.$traceID.withValue(1234) { // bind the value print("traceID: \(Example.traceID)") // traceID: 1234 read() // traceID: 1234 async let id = read() // async let child task, traceID: 1234 await withTaskGroup(of: String.self) { group in group.addTask { read() } // task group child task, traceID: 1234 return await group.next()! } Task { // unstructured tasks do inherit task locals by copying read() // traceID: 1234 } Task.detached { // detached tasks do not inherit task-local values read() // traceID: nil } } ``` ```swift let taskA = Task { @MainActor in let a = await fnA(); } let taskB = Task { @MainActor in let b = await fnB(); } let taskC = Task { @MainActor in let c = await fnC(); } actor A { @MainActor func a() { } } ``` ```swift func A() async { print("a") print("b") await B() } func B() async { print("c") print("d") await C() } func C() async { print("e") print("f") } func run() async { print("run 싀행됨") } Task { @MainActor in A() } Task { runt() } // 좜λ ₯ a // 좜λ ₯ b ``` > ν•˜λ‚˜μ˜ μŠ€λ ˆλ“œμ—μ„œ μ‹€ν–‰ > [a,b,c] -> [c, b, a] => [b,c,a] - (μ‹€ν–‰ μ™„λ£Œμ˜ μˆœμ„œ 보μž₯이 μ•ˆλœλ‹€) - Task vs Task.detached => 병렬 μž‘μ—…μ„ ν•΄μ€Œ - 비ꡬ쑰적 λ™μ‹œμ„± - Task: 메타데이터 상속 - Task.detached: 메타데이터 상속 x ```swift let parentTask: Task<Void, Error> = Task { let taskA = Task { print(Task.isCancelled) return "Wow" } let taskB: Task<String,Error> = Task { print(Task.isCancelled) return "Hello" } await [taskA.value, taskB.value] } parentTask.cancel() func childrenRun() async { print(Task.isCancelled) } let asyncTask = Task { async let children1 = childrenRun() // μ—¬κΈ°μ„œ λ³‘λ ¬λ‘œ μž‘λ™ν•¨ async let children2 = childrenRun() // μ—¬κΈ°μ„œ λ³‘λ ¬λ‘œ μž‘λ™ν•¨ // await children1 // μž‘λ™μ΄ 이미 λ‹€ λ˜μ—ˆμœΌλ©΄ κ°’ λ„˜κΈ°κ³ , μ•„λ‹ˆλ©΄ μž‘μ—… μ™„λ£Œλœ λŒ€λ‘œ κ°’ λ„˜κΉ€... // await children2 await [children2, children1] // 배열이 μ±„μ›Œμ§ˆ λ•Œ κΉŒμ§€ κΈ°λ‹€λ¦°λ‹€.. } asyncTask.cancel() ``` - async let vs withTaskGroup => 병렬 μž‘μ—…μ„ ν•΄μ€Œ - ꡬ쑰적 λ™μ‹œμ„± - - What is async-await - μž‘μ—… μˆœμ„œλ₯Ό μ•„λŠ” 방법? - awaitλ₯Ό ν•  λ•Œ call stack - 메타 λ°μ΄ν„°λž€ 무엇인가? - Task.detached() - μŠ€λ ˆλ“œ ν’€ - Task.yield() - https://engineering.linecorp.com/ko/blog/about-swift-concurrency-performance ```swift Task { @MainActor for i in 1200000000 { if i % 10 == 0 { Task.yield() } print(i) } } ``` ### 였늘 ν•œ 것과 μ’€ 더 봐야할 것 1. TaskLocal => 바인딩, TCA κ°œλ… - μ‹€μ œλ‘œ μ“°λŠ” 사둀... ### λ‹€μŒμ— ν•  것 1. ⭐️ **Shared Mutable State** 2. Task isolation 3. Race Condition 문제 4. Sendable 5. actor κ°œλ…λ§Œ... ## Actor / AsyncStream - AsyncStream?