🔥 비동기 시퀀스

363자
5분

비동기 시퀀스는 Swift의 강력한 기능 중 하나로, 컬렉션의 요소를 하나씩 기다리면서 순차적으로 처리할 수 있게 해줍니다. 이전 섹션에서 살펴본 listPhotos(inGallery:) 함수는 배열의 모든 요소가 준비된 후에 한 번에 전체 배열을 비동기적으로 반환했죠. 하지만 비동기 시퀀스를 사용하면 컬렉션의 요소를 하나씩 기다리는 또 다른 접근 방식을 사용할 수 있습니다.

비동기 시퀀스를 순회하는 코드는 다음과 같습니다:

import Foundation
 
let handle = FileHandle.standardInput
for try await line in handle.bytes.lines {
    print(line)
}
swift

일반적인 for-in 루프 대신에, 위의 예제에서는 for 다음에 await을 작성하고 있어요. 비동기 함수나 메서드를 호출할 때와 마찬가지로, await을 작성하는 것은 실행이 일시 중단될 수 있는 지점을 나타냅니다. for-await-in 루프는 다음 요소를 사용할 수 있을 때까지 기다리는 동안 각 반복의 시작 부분에서 실행을 일시 중단할 수 있어요.

for-in 루프에서 자신만의 타입을 사용하기 위해 Sequence 프로토콜을 준수하도록 추가하는 것과 같은 방식으로, AsyncSequence 프로토콜을 준수하도록 추가하여 for-await-in 루프에서 자신만의 타입을 사용할 수 있습니다.

예를 들어, 파일에서 줄을 읽어오는 작업을 비동기 시퀀스로 구현해 볼까요?

import Foundation
 
// 파일에서 줄을 읽어오는 비동기 시퀀스
struct LineSequence: AsyncSequence {
    typealias Element = String
    let url: URL
 
    // 비동기 이터레이터
    struct AsyncIterator: AsyncIteratorProtocol {
        let handle: FileHandle
 
        mutating func next() async throws -> String? {
            // 파일에서 데이터 읽기
            guard let data = try await handle.read(upToCount: 1024) else {
                return nil
            }
            // 데이터를 문자열로 변환하여 반환
            return String(decoding: data, as: UTF8.self)
        }
    }
 
    // 비동기 이터레이터 생성
    func makeAsyncIterator() -> AsyncIterator {
        let fileHandle = try! FileHandle(forReadingFrom: url)
        return AsyncIterator(handle: fileHandle)
    }
}
 
// 파일 URL
let fileURL = URL(fileURLWithPath: "path/to/file.txt")
 
// 비동기 시퀀스 생성
let lines = LineSequence(url: fileURL)
 
// 비동기 시퀀스 순회
for try await line in lines {
    print(line)
}
swift

위 코드에서는 LineSequence라는 비동기 시퀀스를 정의하고 있습니다. 이 시퀀스는 주어진 URL의 파일에서 줄을 읽어오는 역할을 합니다.

AsyncIterator 구조체는 AsyncIteratorProtocol을 채택하여 비동기 이터레이터를 구현하고 있어요. next() 메서드는 파일에서 데이터를 읽어와 문자열로 변환하여 반환합니다. 파일의 끝에 도달하면 nil을 반환하죠.

makeAsyncIterator() 메서드는 AsyncIterator 인스턴스를 생성하여 반환합니다. 이 메서드는 주어진 URL의 파일을 열고 FileHandle을 사용하여 파일을 읽을 준비를 합니다.

마지막으로, for-await-in 루프를 사용하여 LineSequence를 순회하면서 파일의 각 줄을 출력하고 있습니다.

이처럼 비동기 시퀀스를 활용하면 컬렉션의 요소를 하나씩 처리하면서 비동기 작업을 수행할 수 있습니다. 이는 대용량 데이터를 다룰 때 특히 유용하겠죠? 메모리 사용량을 줄이고 효율적으로 처리할 수 있습니다.