[Swift] Swift concurrency 동작 구조

Young Bin Lee·2022년 7월 31일
0

References

서론

  • 첫번째는 sync 코드 두번째는 async 코드이며 우리가 지금까지 잘 사용해 왔던 구조입니다.

  • 비동기 코드를 사용하였을 때 시퀀셜한 작업이 필요한 순간 위와 같이 completion을 적절히 이용해서 결과를 처리해왔습니다.

async/await

  • async/await를 사용하면 이제 그러지 않아도 됩니다.

Testing async

테스트 할 때도 마찬가지입니다. 예전엔 XCExpectation을 썼는데


이제는 더 편해졌습니다.


AsyncSequence

Sequence가 뭘까요

A sequence is a list of values that you can step through one at a time. The most common way to iterate over the elements of a sequence is to use a for-in loop:

Iterator같은 느낌인데 또 Iterator는 아닙니다. Sequence를 채택한 대표적인 타입은 Array, Set, Dictionary 등의 Collection이 있는데 IteratorProtocol을 채택하거나 makeIterator를 구현하면 커스텀 타입도 Iterator가 되어 for in 문법을 채택할 수 있습니다.

var iterator = values.makeIterator()
while let value = iterator.next() {
	// Do something	
}
struct Countdown: Sequence, IteratorProtocol {
    var count: Int

    mutating func next() -> Int? {
        if count == 0 {
            return nil
        } else {
            defer { count -= 1 }
            return count
        }
    }
}

let threeToGo = Countdown(count: 3)
for i in threeToGo {
    print(i)
}

Expected Performance

Document에서 발췌

A sequence should provide its iterator in O(1). The Sequence protocol makes no other requirements about element access, so routines that traverse a sequence should be considered O(n) unless documented otherwise.

iterator는 O(1)의 복잡도로 제공되므로 시퀀스를 횡단하는 동작은 별다른 표기가 없다면 O(n)이 될 것입니다.

Async에서의 Sequence

AsyncSequence는 Async Task들이 시퀀스로 구현되어있는 형태입니다. 예시부터 보면,

struct QuakesTool {
    static func main() async throws {
        let endpointURL = URL(string: "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.csv")!

        for try await event in endpointURL.lines.dropFirst() {
            let values = event.split(separator: ",")
            let time = values[0]
            let latitude = values[1]
            let longitude = values[2]
            let magnitude = values[4]
            print("magnitude: \(magnitude), time: \(time), latitude: \(latitude), longitude: \(longitude)")
        }
    }
}

  • 배열을 다루듯 자유롭게 event를 관리하고 dropFirst를 사용할 수도 있습니다. Sequence에서 사용하는 함수 중 상당수가 사용 가능합니다.
  • AsyncSequence는 그룹으로 관리되어 그룹 안에 속하는 모든 Task가 완료 시 배열 전체를 한꺼번에 비동기 반환합니다.
  • 참고로 이 케이스(URL.lines)에서는 task 완료 순서대로 for문 안의 context를 실행시킵니다. 즉, Task가 실행되는 데에는 정해진 순서가 없습니다.

  • 필터도 됩니다.

  • 여튼 보셨다시피 AsyncSequence는 그냥 Async가 붙은 시퀀스입니다.
  • 현 context에서 에러를 던질 수도 완료, 에러로 인해 종료될 수도 있습니다.

동작 원리

  • Iterator가 async가 아닌 그냥 일반적인 경우라면 for in 안에서 컴파일러는 Iterator를 이런 식으로 핸들링합니다
  • for in을 while let으로 치환합니다

  • async라고 크게 다를 것은 없습니다.
  • 다만 일반 시퀀스처럼 처리하면 await으로 대기처리를 할 수 없으니 약간의 코드가 더해집니다.

  • 이런식으로
profile
I can make your dream come true

0개의 댓글