Search code examples
swiftasync-awaitconcurrencyswift-concurrency

Swift Group Tasks not running in parallel


Questions:

  • Why are the group tasks not running in parallel?
  • Am I missing something or is this a bug?

Output:

started 24
finished 24
--- 24
started 12
finished 12
--- 12
started 16
finished 16
--- 16
started 4
finished 4
--- 4
started 10
finished 10
--- 10
started 20
finished 20
--- 20
started 19
finished 19
--- 19

Environment:

  • macOS 11.5.2 (20G95)
  • Xcode Version 13.0 beta 5 (13A5212g)
  • SwiftUI project

Code:

func groupTask() async -> [Int : Int] {
    let ids = [24, 12, 16, 4, 10, 20, 19]
    var prices = [Int : Int]()
    
    for id in ids {
        await withTaskGroup(of: (Int, Int).self) { group in
            group.addTask(priority: .background) {
                let price = await computePrice(for: id)
                return (id, price)
            }
            
            for await (id, price) in group {
                prices[id] = price
                print("--- \(id)")
            }
        }
    }
    
    return prices
}


func computePrice(for id: Int) async -> Int {
    print("started \(id)")
    let duration = UInt64(id * 100_000_000)
    await Task.sleep(duration)
    print("finished \(id)")
    return id * 2
}

Solution

  • Why are the group tasks not running in parallel?

    You have await withTaskGroup inside for-in, so your code waits for the group task to finish at each iteration.

    You may want to do something like this?

        func groupTask() async -> [Int : Int] {
            let ids = [24, 12, 16, 4, 10, 20, 19]
            var prices = [Int : Int]()
            
            await withTaskGroup(of: (Int, Int).self) { group in
                for id in ids {
                    group.addTask(priority: .background) {
                        let price = await computePrice(for: id)
                        return (id, price)
                    }
                }
                
                for await (id, price) in group {
                    prices[id] = price
                    print("--- \(id)")
                }
            }
            
            return prices
        }