You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// Create a new child task for each vegetable that needs to be
252
252
// chopped.
253
253
for v in rawVeggies {
254
-
await group.add {
254
+
await group.spawn {
255
255
return v.chopped()
256
256
}
257
257
}
@@ -288,7 +288,7 @@ A detached task is represented by a task handle (in this case, `Task.Handle<Meal
288
288
let dinner =tryawait dinnerHandle.get()
289
289
```
290
290
291
-
Detached tasks run to completion even if there are no remaining uses of their task handle, so `runDetached` is suitable for operations for which the program does not need to observe completion. However, the task handle can be used to explicitly cancel the operation, e.g.,
291
+
Detached tasks run to completion even if there are no remaining uses of their task handle, so `spawnDetached` is suitable for operations for which the program does not need to observe completion. However, the task handle can be used to explicitly cancel the operation, e.g.,
The `priority` operation queries the priority of the task.
497
497
498
-
Task priorities are set on task creation (e.g., `spawnDetached` or `Task.Group.add`) and can be escalated later, e.g., if a higher-priority task waits on the task handle of a lower-priority task.
498
+
Task priorities are set on task creation (e.g., `spawnDetached` or `TaskGroup.spawn`) and can be escalated later, e.g., if a higher-priority task waits on the task handle of a lower-priority task.
499
499
500
-
The `currentPriority` operation queries the priority of the currently-executing task. Task priorities are set on task creation (e.g., `spawnDetached` or `Task.Group.add`) and can be escalated later, e.g., if a higher-priority task waits on the task handle of a lower-priority task.
500
+
The `currentPriority` operation queries the priority of the currently-executing task. Task priorities are set on task creation (e.g., `spawnDetached` or `TaskGroup.spawn`) and can be escalated later, e.g., if a higher-priority task waits on the task handle of a lower-priority task.
501
501
502
502
#### Task handles
503
503
@@ -562,14 +562,14 @@ A new, detached task can be created with the `spawnDetached` operation. The resu
562
562
```swift
563
563
/// Create a new, detached task that produces a value of type `T`.
564
564
@discardableResult
565
-
staticfuncrunDetached<T: Sendable>(
565
+
staticfuncspawnDetached<T: Sendable>(
566
566
priority: Priority = .default,
567
567
operation: @escaping@concurrent () async-> T
568
568
) -> Task.Handle<T, Never>
569
569
570
570
/// Create a new, detached task that produces a value of type `T` or throws an error.
571
571
@discardableResult
572
-
staticfuncrunDetached<T: Sendable>(
572
+
staticfuncspawnDetached<T: Sendable>(
573
573
priority: Priority = .default,
574
574
operation: @escaping@concurrent () asyncthrows-> T
`Task.Group` has no public initializers; instead, an instance of `Task.Group` is passed in to the `body` function of `withTaskGroup`. This instance should not be copied out of the `body` function, because doing so can break the child task structure.
885
+
`TaskGroup` has no public initializers; instead, an instance of `TaskGroup` is passed in to the `body` function of `withTaskGroup`. This instance should not be copied out of the `body` function, because doing so can break the child task structure.
885
886
886
887
> **Note**: Swift does not currently have a way to ensure that the task group passed into the `body` function is not copied elsewhere, so we therefore rely on programmer discipline in a similar manner to, e.g., [`Array.withUnsafeBufferPointer`](https://developer.apple.com/documentation/swift/array/2994771-withunsafebufferpointer). However, in the case of task groups, we can at least provide a runtime assertion if one attempts to use the task group instance after its corresponding scope has ended.
887
888
@@ -937,6 +938,18 @@ The `next()` operation allows one to gather the results from the tasks that have
937
938
938
939
```swift
939
940
extensionTaskGroup: AsyncSequence {
941
+
/// Wait for a task to complete and return the result it returned (or throw if the task
942
+
/// exited with a thrown error), or else return `nil` when there are no tasks left in
943
+
/// the group.
944
+
mutatingfuncnext() async-> TaskResult? { ... }
945
+
946
+
/// Query whether the task group has any remaining tasks.
947
+
var isEmpty: Bool { ... }
948
+
}
949
+
```
950
+
951
+
```swift
952
+
extensionThrowingTaskGroup: AsyncSequence {
940
953
/// Wait for a task to complete and return the result it returned (or throw if the task
941
954
/// exited with a thrown error), or else return `nil` when there are no tasks left in
The `next()` operation may typically be used within a `while` loop to gather the results of all outstanding tasks in the group, e.g.,
955
968
956
969
```swift
970
+
whilelet result =await group.next() {
971
+
// some accumulation logic (e.g. sum += result)
972
+
}
973
+
974
+
// OR
975
+
957
976
whilelet result =tryawait group.next() {
958
977
// some accumulation logic (e.g. sum += result)
959
978
}
960
979
```
961
980
962
-
`Task.Group` also conforms to the [`AsyncSequence` protocol](https://github.com/apple/swift-evolution/blob/main/proposals/0298-asyncsequence.md), allowing the child tasks' results to be iterated in a `for await` loop:
981
+
`TaskGroup` also conforms to the [`AsyncSequence` protocol](https://github.com/apple/swift-evolution/blob/main/proposals/0298-asyncsequence.md), allowing the child tasks' results to be iterated in a `for await` loop:
982
+
963
983
```swift
964
984
forawait result in group { // non-throwing TaskGroup
* Creating a child task will eventually be `spawn <something>`
1087
1107
* Moving away from using `Task` as namespace for everything
1088
-
* rename `Task.Group` to `TaskGroup`
1108
+
* rename `TaskGroup` to `TaskGroup`, and introduce `ThrowingTaskGroup`
1089
1109
* make `Task.unsafeCurrent` a free function`withUnsafeCurrentTask`
1090
1110
* Task group type parameter renames: `TaskGroup<TaskResult>` becomes `ChildTaskResult` resulting in: `public func withTaskGroup<ChildTaskResult, GroupResult>(of childTaskResultType: ChildTaskResult.Type, returning returnType: GroupResult.Type = GroupResult.self, body: (inout TaskGroup<ChildTaskResult>) async throws -> GroupResult) async rethrows -> GroupResult` resulting in a more readable call site: `withTaskGroup(of: Int.self)` and optionally `withTaskGroup(of: Int.self, returning: Int.self)`
1091
1111
* For now remove `startingChildTasksOn` from `withTaskGroup` since this is only doable with Custom Executors which are pending review still.
@@ -1097,7 +1117,7 @@ Changes after first review:
1097
1117
* Factored `async let` into [its own proposal](https://github.com/DougGregor/swift-evolution/pull/50).
1098
1118
*`Task` becomes a `struct` with instance functions, introduction of `Task.current`, `Task.unsafeCurrent` and the `UnsafeCurrentTask` APIs
1099
1119
*`Task.Group` now conforms to [the `AsyncSequence` protocol](https://github.com/apple/swift-evolution/blob/main/proposals/0298-asyncsequence.md).
1100
-
*`spawnDetached` and `Task.Group.add` now accept [executor](https://github.com/apple/swift-evolution/pull/1257) arguments to specify where the newly-spawned tasks are initially scheduled.
1120
+
*`spawnDetached` and `Task.group.spawn` now accept [executor](https://github.com/apple/swift-evolution/pull/1257) arguments to specify where the newly-spawned tasks are initially scheduled.
1101
1121
* Changes in the second pitch:
1102
1122
* Added a "desugaring" of `async let` to task groups and more motivation for the structured-concurrency parts of the design.
1103
1123
* Reflowed the entire proposal to focus on the general description of structured concurrency first, the programming model with syntax next, and then details of the language features and API design last.
@@ -1117,7 +1137,7 @@ Changes after first review:
1117
1137
1118
1138
The design of task groups intentionally avoids exposing any task handles (futures) for child tasks. This ensures that the structure of structured concurrency, where all child tasks complete before their parent task, is maintained. That helps various properties such as priorities, deadlines, and cancellation to propagate in a meaningful way down the task tree.
1119
1139
1120
-
However, an alternative design would bring futures to the forefront. One could introduce an `runChild` counterpart to `runDetached` that creates a new child task (of the current task), and then retrieve the result of that child task using the provided `Task.Handle`. To ensure that child tasks complete before the scope exits, we would require some kind of scoping mechanism that provides similar behavior to task groups. For example, the `makeDinner` example would be something like:
1140
+
However, an alternative design would bring futures to the forefront. One could introduce an `runChild` counterpart to `spawnDetached` that creates a new child task (of the current task), and then retrieve the result of that child task using the provided `Task.Handle`. To ensure that child tasks complete before the scope exits, we would require some kind of scoping mechanism that provides similar behavior to task groups. For example, the `makeDinner` example would be something like:
0 commit comments