Skip to content

Commit 0060af5

Browse files
committed
Remove AsyncIterator: Sendable requirement from merge
# Motivation Currently a lot of the operator implementations in here that consume other `AsyncSequence`s require the `AsyncIterator` to be `Sendable`. This is mostly due to the fact that we are calling `makeAsyncIterator` on the upstream `AsyncSequence` and then pass that iterator around to various newly spawned `Task`s. This has two downsides: 1. It only allows users to use operators like `merge` if their `AsyncSequence.AsyncIterator` is `Sendable` 2. In merge we are creating new `Task`s for every new demand. Creating `Task`s is not cheap. My main goal of this PR was to remove the `Sendable` constraint from `merge`. # Modification This PR overhauls the complete inner workings of the `AsyncMerge2Sequence`. It does a couple of things: 1. The main change is that instead of creating new `Task`s for every demand, we are creating one `Task` when the `AsyncIterator` is created. This task has as child task for every upstream sequence. 2. When calling `next` we are signalling the child tasks to demand from the upstream 3. A new state machine that is synchronizing the various concurrent operations that can happen 4. Handling cancellation since we are creating a bunch of continuations. # Result In the end, this PR swaps the implementation of `AsyncMerge2Sequence` and drops the `Sendable` constraint and passes all tests. Furthermore, on my local performance testing I saw up 50% speed increase in throughput. # Open points 1. I need to make this sequence re-throwing but before going down that rabbit whole I wanna get buy-in on the implementation. 2. We should discuss and document if `merge` and other operators are hot or cold, i.e. if they only request if they got downstream demand 3. I need to switch `AsyncMerge3Sequence` over to the same iplementation
1 parent c0fdfdb commit 0060af5

File tree

5 files changed

+1252
-194
lines changed

5 files changed

+1252
-194
lines changed

Package.swift

+9-2
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,16 @@ let package = Package(
1616
.library(name: "_CAsyncSequenceValidationSupport", type: .static, targets: ["AsyncSequenceValidation"]),
1717
.library(name: "AsyncAlgorithms_XCTest", targets: ["AsyncAlgorithms_XCTest"]),
1818
],
19-
dependencies: [],
19+
dependencies: [
20+
.package(url: "https://github.com/apple/swift-collections.git", from: "1.0.2"),
21+
],
2022
targets: [
21-
.target(name: "AsyncAlgorithms"),
23+
.target(
24+
name: "AsyncAlgorithms",
25+
dependencies: [
26+
.product(name: "DequeModule", package: "swift-collections")
27+
]
28+
),
2229
.target(
2330
name: "AsyncSequenceValidation",
2431
dependencies: ["_CAsyncSequenceValidationSupport", "AsyncAlgorithms"]),

0 commit comments

Comments
 (0)