[Swift Concurrency] 작업 취소

정한별·2026년 1월 12일

Swift Concurrency

목록 보기
5/5

작업취소란?

작업 취소란 Task 내부의 비동기 함수들에게 취소 신호를 전파하는 것을 말한다.
구조적 동시성에서 부모 작업은 자식 작업에도 취소를 전파한다.
여기서 취소는 작업을 즉시 중단시키는 강제 종료가 아니라, 각 작업이 취소 신호를 확인하고 스스로 실행을 중단하도록 하는 협력적 취소 Cooperative Cancellation 방식으로 동작한다.

작업취소 방법

Task 직접 취소

func fetch() async throws -> UIImage? {
    try await Task.sleep(nanoseconds: 1_000_000_000)
    return UIImage(named: "")
}

let task = Task {
    for i in 1...10 {
        print("작업 \(i) 진행 중...")
        try await fetch()
    }
}

try await Task.sleep(nanoseconds: 2_000_000_000)
task.cancel()

구조적 동시성에서의 자동 취소 - async let

let task = Task {
    async let data1 = fetch()
    async let data2 = fetch()
    async let data3 = fetch()

    // 부모 Task가 취소되면 data1, data2, data3 모두 자동 취소됨
    return try await [data1, data2, data3]
}


try await Task.sleep(nanoseconds: 500_000_000)
task.cancel()

구조적 동시성에서의 자동 취소 - TaskGroup

let task = Task {
    try await withThrowingTaskGroup(of: UIImage?.self) { group in
        for i in 1...10 {
            group.addTask {
                let image = try await fetch()
                print("작업 \(i) 완료")
                return image
            }
        }

        var results: [UIImage?] = []
        for try await result in group {
            results.append(result)
        }
        return results
    }
}

try await Task.sleep(nanoseconds: 500_000_000)
task.cancel()

TaskGroup에선 그룹 자체에서도 모든 작업을 취소 할 수도 있다.
이것으로 어떤 한개의 작업이 성공했을때 나머지 작업을 취소한다던지, 어떤 한개의 작업이 실패했을때 나머지 작업을 취소한다던지 조건부 취소도 가능하다.

func fetchData(from: String) async throws -> Data {
    try await Task.sleep(nanoseconds: 1_000_000_000)
    return Data()
}

func fetchFromMultipleServers() async throws -> Data {
    return try await withThrowingTaskGroup(of: Data.self) { group in
        let servers = ["server1.com", "server2.com", "server3.com"]

        // 모든 서버에 동시 요청
        for server in servers {
            group.addTask {
                try await fetchData(from: server)
            }
        }

        // 첫 번째 성공한 결과를 받으면 나머지 취소
        guard let firstResult = try await group.next() else {
            throw NSError(domain: "", code: 00)
        }

        // 나머지 작업들 모두 취소
        print("\(firstResult)")
        group.cancelAll()

        return firstResult
    }
}

Task {
    try await fetchFromMultipleServers()
}

취소를 확인할 수 있는 방법.

Task.isCancelled - 상태 확인

취소 상태를 Boolean 값으로 확인한다. 가장 기본적인 방법이다.

func processItems() async throws {
    for i in 1...100 {
        // 취소 확인
        print("작업 \(i)")
        if Task.isCancelled {
            print("작업이 취소되었습니다.")
            return // 직접 종료
        }

        // 실제 작업 수행
        try await fetch()
    }
}

let task = Task {
    try await processItems()
}

Task {
    try await Task.sleep(nanoseconds: 5_000_000_000)
    task.cancel()
}

2. Task.checkCancellation() - 자동 에러 발생

취소되었다면 자동으로 CancellationError를 던진다. throws 함수에서 사용하기 좋다.

func fetchData() async throws -> [String] {
    var results: [String] = []

    for i in 1...100 {
        // 취소되면 자동으로 CancellationError 발생
        print("작업 \(i)")
        try Task.checkCancellation()
        try await Task.sleep(nanoseconds: 1_000_000_000)
        results.append("data")
    }

    return results
}

let task = Task {
    do {
        try await fetchData()
    } catch {
        print("error: \(error)")
    }
}

Task {
    try await Task.sleep(nanoseconds: 5_000_000_000)
    task.cancel()
}
profile
iOS Developer

0개의 댓글