# TaskGroup vs an array of tasks

**URL:** <https://forums.swift.org/t/taskgroup-vs-an-array-of-tasks/53931>\
**Category:** Using Swift\
**Tags:** concurrency\
**Created:** [December 8, 2021, 8:36pm UTC](https://forums.swift.org/t/taskgroup-vs-an-array-of-tasks/53931 "2021-12-08T20:36:07Z")\
**Posts on this page:** 1\
**Showing post:** 2

<div class="post-metadata">

**Author:** ![ktoso](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ktoso/32/44526_2.png) [@ktoso](https://forums.swift.org/u/ktoso)\
**Post date:** [December 8, 2021, 9:46pm UTC](https://forums.swift.org/t/taskgroup-vs-an-array-of-tasks/53931/2 "2021-12-08T21:46:19Z")

</div>

> [@Frizlab](#):
>
> I understand a TaskGroup allows retrieving tasks results “continuously” ( **I get the result of first task that succeed, then the next, etc.** ), as opposed to an array of tasks where I cannot guess which task will finish first and I have to decide the order in which I’ll await the tasks.

Correct, the defining feature of a group is collecting results in completion order. You cannot write this as efficiently using other techniques (Just `Task{}` and a stream etc will be heavier memory and scheduling wise than what a group does).

> [@Frizlab](#):
>
> But if I need the results of all the tasks anyway, is there any other hidden benefits from a task group that should make me prefer it over simply storing the tasks in an array and waiting for them in order?

You'll have to do one of the two things if you wanted to not use a group:

1. spawn one by one, no parallelism:

```swift
for work in works { 
  let t = await work.work()
  things.append(t)
}

```

That is meh since it is not parallel at all. So you might write this instead:

1. some (unbounded - meh) parallelism

```swift
for work in works { 
  Task {
    let t = await work.work()
    await self.append(t)
  }
}

func append(t: T) async { 
  self.things.append(t)
}

```

which is meh for a number of reasons:

- unbounded parallelism is meh in general, this just throws all the tasks at the scheduler without much control over how many are in flight at any point in time (whereas implementing such limiting is simple in a group)
- you had to use unstructured tasks (`Task{}`) which are _heavier_ than task group created tasks (`group.addTask{}` - this is a child task and is _very_ efficient)
  - you're missing out on structured concurrency entirely; so propagation of task-locals is more expensive in this, as well as there being no guarantee whatsoever that all tasks complete before you "proceed" while tasks in a group keep the group waiting until they all complete

- you cannot collect the results on the task kicking off the work easily... so you'll either pay additional hops like shown above, or you'll have to invent your own way to message into an async stream from there...

So... use a group instead for those patterns, it handles them very well 😉 👍

```swift
withTaskGroup(of: T.self) { group in 
  for t in tasks { 
    group.addTask { await t } // efficient child task
  }
  for await t in group { // efficiently gathering in completion order
    // back in calling task
    things.append(t)
  }
} // always guaranteed to have drained all the tasks

```

---

_[View the full topic](https://forums.swift.org/t/taskgroup-vs-an-array-of-tasks/53931)._
