본문 바로가기

학습활동

Swift Concurrency I

Coroutine

Swift Concurrency

  • 병렬 프로그래밍과 비동기 코드를 사용하는 프로그램은 한번에 여러 작업을 수행할 수 있음
  • Swift안에서 Concurrency 모델은 스레드에서 구축하지만 스레드와 직접 상호 작용하지는 않음
  • → 비동기 함수가 Blocking이 되면 시스템에 맡김
  • → 비동기 함수가 다시 resume되면 해당 함수가 어느 스레드에서 실행될지는 보장되지 않음
  • → 비동기 함수가 Blocking 시 실행 중이던 스레드를 포기할 수 있게 되고, 해당 스레드는 다른 비동기 함수를 실행할 수 있음
  • 이 개념은 코루틴(Coroutine) 에서 출발
  •  Swift의 Async/Await 은 코루틴 모델을 적용!
  • async는 함수를 suspend(중단) 시키고, 다시 resume(재개)을 할 수 있지만 한번에 한 부분의 프로그램만 실행
  • async를 붙임으로 비동기 함수임을 명시
    func listPhotos(inGallery name: String) async throws -> [String] {
        let result = // ... some asynchronous networking code ...
        return result
    }
    
  • → error를 던지면서 비동기인 경우
  • await 키워드를 만나면 스레드를 Block하고 async 메서드의 반환값을 받을 때까지 일시 중단
  •  즉, await 키워드가 중단을 시키는 지점
  •  비동기 메서드 안에 또다른 비동기 메서드가 있으면 모두 await을 명시적으로 적어줘야함
// completion handler 사용 예시
listPhotos(inGallery: "Summer Vacation") { photoNames in
    let sortedNames = photoNames.sorted()
    let name = sortedNames[0]
    downloadPhoto(named: name) { photo in
        show(photo)
    }
}

// async-await 사용 예시
let photoNames = await listPhotos(inGallery: "Summer Vacation")
let sortedNames = photoNames.sorted()
let name = sortedNames[0]
let photo = await downloadPhoto(named: name)
show(photo)
  • await은 코드가 실행 중단 가능한 위치에서만 호출이 가능
    • 비동기 함수, 메서드, 프로퍼티, 이니셜라이즈(getter만)
    • @main으로 표시된 struct, class, enum의 static main() 메서드
    • Unstructed Concurrency의 unstructed child task
  • await 코드들 사이의 코드는 다른 동시성 코드로 인한 방해없이 순차적으로 진행됨
  • → await을 사용하면 안되는 순차적인 코드의 경우, 이를 명시하기 위해 코드를 묶어라
  • // 꼽사리가 가능한 경우
    let firstPhoto = await listPhotos(inGallery: "Summer Vacation")[0]
    add(firstPhoto, toGallery: "Road Trip")
    // At this point, firstPhoto is temporarily in both galleries.
    remove(firstPhoto, fromGallery: "Summer Vacation")
    
    // 여기에 awiat 붙이지마라는 경우
    // move는 비동기 함수가 아니기 때문에 add, remove에 await을 붙일 수 없게 됨
    func move(_ photoName: String, from source: String, to destination: String) {
        add(photoName, toGallery: destination)
        remove(photoName, fromGallery: source)
    }
    // ...
    let firstPhoto = await listPhotos(inGallery: "Summer Vacation")[0]
    move(firstPhoto, from: "Summer Vacation", to: "Road Trip")
    

Suspend란?

  • 동기 메서드는 스레드가 해당 메서드를 모두 수행했을 때 스레드에 대한 control을 잃음
  • 비동기 메서드는 동작 수행 완료 시, 그리고 시스템에 의해 스레드 control을 잃을 수 있음
  • 비동기 메서드가 await이 되어 결과가 반환할 때까지 기다리는 동안 실행을 일시 중단(suspend)
  • → 이때 스레드 제어권(control)을 잃음
main thread ———- async를 thread1에 던짐(비동기)
thread 1 : async 호출 —- await (스레드 제어권을 놓는다) 스레드가 비워져서 다른 코드를 실행할 수 있어짐
    → 이것이 await으로 이름을 진 이유
    → 스레드가 차단되는 것이 아니기 때문에 시스템은 다른 작업을 예약할 수 있음
    → 기능이 일시중지되어 있는 동안 앱의 상태가 크게 변할 수도 있음
스레드 양보 → 스레드에 대한 제어권은 시스템에게 감
시스템 : async의 리턴값을 계산하는 작업을 다하고 다시 스레드로 돌아오지만 thread 1으로 복귀한다는 보장은 없음
    → 시스템이 async함수가 중요도가 높다고 판단하면 다시 함수 재개한다
await로 async를 호출한 경우를 언제, 몇번 일시정지가 되고 재개될지 알 수 없고, 시스템이 자체적으로 중요도와 작업 상태를 결정하는 것이기 때문에 일시정지없이 실행될 수도 있다

 

참고 링크

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/concurrency/

728x90

'학습활동' 카테고리의 다른 글

동시성 프로그래밍  (0) 2023.11.08
Swift Concurrency II  (0) 2023.09.28
User Notifications  (0) 2023.09.25
OAuth(Open Authorization)  (0) 2023.09.21
Localization  (0) 2023.08.31