How to call async/await functions concurrently in Swift
Learn how to call async/await functions in parallel with tasks.
30 Jun 2021 · 4 min read
As we have learned in this guide on async/await in Swift, calling an asynchronous function with await runs only one piece of code at a time. The caller waits for it to finish before running the next line of code.
Sometimes, we want to be able to start multiple async functions in parallel because they don't depend on each other. This is where tasks come in.
Calling asynchronous functions concurrently with tasks
Tasks are a new feature in Swift version 5.5 that work hand in hand with the new async/await functionality. Each task runs concurrently, so tasks allow us to call asynchronous functions in parallel.

Instead of directly calling await on a async function, we can use the async-let binding to create a task which provides a new async context for executing code concurrently.
Sequential binding:
let profileImage = await URLSession.shared.data(...)let headerImage = await URLSession.shared.data(...)
Concurrent binding:
async let profileImageTask = URLSession.shared.data(...)async let headerImageTask = URLSession.shared.data(...)let profileImage = await profileImageTasklet headerImage = await headerImageTask
With the concurrent binding approach, we created two child tasks that start independently without waiting for the previous one to complete.
Group tasks
Additionally to async-let tasks, Swift provides group tasks.
Group tasks are designed to provide a dynamic amount of concurrency, i.e. they are perfect for situations, where we don't know the amount of concurrent tasks from the beginning, for example when fetching thumbnails from an array of urls.
func downloadImages(imageURLs: [URL]) async throws -> [UIImage] {var results: [UIImage] = []try await withThrowingTaskGroup(of: (Data, URLResponse).self, body: { taskGroup infor imageURL in imageURLs {taskGroup.async { try await URLSession.shared.data(from: imageURL) }}while let data = try await taskGroup.next(), let image = UIImage(data: data.0) {results.append(image)}})return results}
Each task in a group has the same parent task, and each task can have child tasks. Because tasks are arranged in a hierarchy, this approach is called structured concurrency.

Newsletter
Like to support my work?
Say hi
Related tags
Articles with related topics
Latest articles and tips