Swift Concurrency 동시성을 쉽게 설명해볼게요!

작성일 :

Swift Concurrency 동시성을 쉽게 설명해볼게요!

Swift 5.5에서 도입된 동시성(Concurrency) 기능은 Swift 언어에 큰 변화를 가져왔습니다. 동시성은 여러 작업을 동시에 실행하여 성능을 향상시키고, 사용자 경험을 개선할 수 있는 중요한 개념입니다. 이 글에서는 Swift의 동시성 개념을 쉽게 설명하고, 이를 활용하는 방법에 대해 알아보겠습니다.

동시성이란?

동시성은 여러 작업을 동시에 실행하는 능력을 말합니다. 이는 멀티태스킹의 기본 요소로, 현대적인 애플리케이션에서는 필수적입니다. 예를 들어, 동시성을 사용하면 사용자가 앱을 사용하는 동안 백그라운드에서 데이터를 다운로드하거나 처리할 수 있습니다.

전통적인 동시성 접근법

기존의 Swift에서는 동시성을 구현하기 위해 GCD(Grand Central Dispatch)나 OperationQueue를 사용했습니다. 하지만, 이러한 방법은 코드가 복잡해지고 가독성이 떨어질 수 있습니다.

swift
DispatchQueue.global().async {
    // 백그라운드 작업
    DispatchQueue.main.async {
        // 메인 스레드에서 UI 업데이트
    }
}

위의 코드는 비동기 작업을 처리하는 전통적인 방법 중 하나입니다. 이제 Swift Concurrency를 사용하여 더 간단하고 직관적인 방법을 살펴보겠습니다.

Swift Concurrency의 주요 구성 요소

Swift Concurrency는 async/await 구문과 Task를 통해 동시성을 보다 쉽게 구현할 수 있도록 합니다.

async와 await

asyncawait 키워드는 비동기 작업을 처리하는 새로운 방법입니다. async 함수는 비동기 작업을 수행하며, await 키워드는 비동기 작업의 결과를 기다립니다.

swift
import Foundation

func fetchUserData() async -> String {
    // 네트워크 요청을 시뮬레이션하기 위해 2초 대기
    try? await Task.sleep(nanoseconds: 2 * 1_000_000_000)
    return "User Data"
}

func displayUserData() async {
    let data = await fetchUserData()
    print(data)
}

Task {
    await displayUserData()
}

위의 예제에서 fetchUserData 함수는 비동기 작업을 수행하고, displayUserData 함수는 await 키워드를 사용하여 이 작업의 결과를 기다립니다. Task 블록은 비동기 컨텍스트에서 함수를 호출하는 방법입니다.

Task

Task는 비동기 작업을 실행하는 단위입니다. Task를 사용하여 비동기 작업을 생성하고 실행할 수 있습니다.

swift
Task {
    let data = await fetchUserData()
    print(data)
}

위의 예제에서는 Task를 사용하여 fetchUserData 함수를 비동기적으로 호출하고, 결과를 출력합니다.

TaskGroup

TaskGroup은 여러 개의 비동기 작업을 그룹화하여 동시에 실행할 수 있도록 합니다. 이를 통해 병렬 처리를 쉽게 구현할 수 있습니다.

swift
import Foundation

func fetchMultipleUserData() async {
    await withTaskGroup(of: String.self) { group in
        group.addTask {
            return await fetchUserData()
        }
        group.addTask {
            return await fetchUserData()
        }

        for await result in group {
            print(result)
        }
    }
}

Task {
    await fetchMultipleUserData()
}

위의 예제에서는 withTaskGroup을 사용하여 두 개의 fetchUserData 작업을 동시에 실행하고, 결과를 출력합니다.

동시성을 사용한 실제 예제

이제 동시성을 사용하여 실제 애플리케이션에서 네트워크 요청을 처리하는 예제를 살펴보겠습니다.

네트워크 요청 예제

swift
import Foundation

struct User: Decodable {
    let id: Int
    let name: String
}

func fetchUser(id: Int) async throws -> User {
    let url = URL(string: "https://jsonplaceholder.typicode.com/users/\(id)")!
    let (data, _) = try await URLSession.shared.data(from: url)
    let user = try JSONDecoder().decode(User.self, from: data)
    return user
}

func displayUser() async {
    do {
        let user = try await fetchUser(id: 1)
        print("User ID: \(user.id), User Name: \(user.name)")
    } catch {
        print("Failed to fetch user: \(error)")
    }
}

Task {
    await displayUser()
}

위의 예제에서는 fetchUser 함수를 사용하여 네트워크 요청을 비동기적으로 수행하고, displayUser 함수에서 결과를 출력합니다. Task 블록을 사용하여 비동기 컨텍스트에서 displayUser 함수를 호출합니다.

결론

Swift Concurrency는 비동기 작업을 보다 쉽고 직관적으로 처리할 수 있도록 도와줍니다. asyncawait 키워드를 사용하면 복잡한 비동기 코드를 간결하게 작성할 수 있으며, TaskTaskGroup을 통해 병렬 처리를 쉽게 구현할 수 있습니다. Swift Concurrency를 활용하여 성능을 향상시키고 사용자 경험을 개선하는 앱을 개발해 보세요.