Skip to content

[Repo Assist] Add AsyncSeq.mapAsyncParallelThrottled — ordered, bounded-concurrency parallel map#312

Merged
dsyme merged 4 commits intomainfrom
repo-assist/improve-map-async-parallel-throttled-20260415-b652b2a1157a8dda
Apr 17, 2026
Merged

[Repo Assist] Add AsyncSeq.mapAsyncParallelThrottled — ordered, bounded-concurrency parallel map#312
dsyme merged 4 commits intomainfrom
repo-assist/improve-map-async-parallel-throttled-20260415-b652b2a1157a8dda

Conversation

@github-actions
Copy link
Copy Markdown
Contributor

🤖 This PR was created by Repo Assist, an automated AI assistant.

Summary

Adds AsyncSeq.mapAsyncParallelThrottled, completing the parallel map API matrix:

Function Order preserved Concurrency
mapAsyncParallel ✅ ordered unbounded (ThreadPool)
mapAsyncUnorderedParallel ❌ unordered unbounded (ThreadPool)
mapAsyncUnorderedParallelThrottled ❌ unordered bounded (parallelism)
mapAsyncParallelThrottled ✅ ordered bounded (parallelism) ← NEW

Motivation

Users often want ordered results (predictable output order, easy diffing, deterministic logging) but also want to cap resource usage — e.g. limiting HTTP connections, database queries, or expensive computations to N concurrent operations. Previously this required building a custom wrapper around mapAsyncParallel or using the unordered variant and accepting non-deterministic output order. mapAsyncParallelThrottled fills this gap directly.

API

/// Builds a new asynchronous sequence whose elements are generated by
/// applying the specified function to all elements of the input sequence,
/// with at most <c>parallelism</c> mapping operations running concurrently.
///
/// The function is applied to elements in order and results are emitted in order,
/// but in parallel, with at most <c>parallelism</c> operations running concurrently.
/// This is the throttled counterpart to <c>mapAsyncParallel</c>.
val mapAsyncParallelThrottled : parallelism:int -> mapping:('T -> Async<'U>) -> s:AsyncSeq<'T> -> AsyncSeq<'U>

Implementation

The implementation combines the ordering logic of mapAsyncParallel (child tasks posted in order, awaited in order) with the SemaphoreSlim throttling from mapAsyncUnorderedParallelThrottled. The semaphore is acquired before starting each task and released when the task completes (success or exception), naturally bounding in-flight work.

Changes

  • src/FSharp.Control.AsyncSeq/AsyncSeq.fs — implementation
  • src/FSharp.Control.AsyncSeq/AsyncSeq.fsi — signature with XML-doc
  • tests/FSharp.Control.AsyncSeq.Tests/AsyncSeqTests.fs — 3 new tests (order preservation, exception propagation, throttle enforcement)
  • RELEASE_NOTES.md — 4.14.0 entry
  • version.props — bumped to 4.14.0

Test Status

Build: succeeded (0 errors, pre-existing warnings only — NU1605, FS9999)
.NET tests: 414/414 passed (3 new tests for mapAsyncParallelThrottled)

Generated by 🌈 Repo Assist, see workflow run. Learn more.

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@97143ac59cb3a13ef2a77581f929f06719c7402a

Generated by 🌈 Repo Assist, see workflow run. Learn more.

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@97143ac59cb3a13ef2a77581f929f06719c7402a

… parallel map

Completes the parallel map API matrix:
- mapAsyncParallel            (ordered, unbounded)
- mapAsyncUnorderedParallel   (unordered, unbounded)
- mapAsyncUnorderedParallelThrottled (unordered, throttled)
- mapAsyncParallelThrottled   (ordered, throttled) ← NEW

Implementation mirrors mapAsyncParallel but adds a SemaphoreSlim
to cap the number of in-flight operations at 'parallelism'. Results
are emitted in source order.

3 new tests: order preservation, exception propagation, throttle enforcement.
414/414 tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@dsyme
Copy link
Copy Markdown
Contributor

dsyme commented Apr 17, 2026

/repo-assist Fable CI is failing

@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 17, 2026

✗ Repo Assist encountered failed, see workflow run.

@dsyme
Copy link
Copy Markdown
Contributor

dsyme commented Apr 17, 2026

/repo-assist Fable CI is failing

@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 17, 2026

✗ Repo Assist encountered failed, see workflow run.

@dsyme
Copy link
Copy Markdown
Contributor

dsyme commented Apr 17, 2026

/repo-assist Fable CI is failing

@github-actions
Copy link
Copy Markdown
Contributor Author

github-actions bot commented Apr 17, 2026

✓ Repo Assist completed successfully, see workflow run.

… NU1605 downgrade warning

System.Threading.Channels 10.0.6 (resolved via Version="*") requires
Microsoft.Bcl.AsyncInterfaces >= 10.0.6, but the project pinned it at 10.0.5.
Fable's MSBuildCrackerResolver treats NU1605 (package downgrade) as a fatal
error, causing the Fable CI job to fail. Bumping to 10.0.6 resolves the conflict.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor Author

Commit pushed: 41e69f1

Generated by 🌈 Repo Assist, see workflow run. Learn more.

@github-actions
Copy link
Copy Markdown
Contributor Author

🤖 Repo Assist here.

Root cause of Fable CI failure: System.Threading.Channels Version="*" resolved to 10.0.6, which requires Microsoft.Bcl.AsyncInterfaces >= 10.0.6. But the project pinned it at 10.0.5, producing a NU1605 downgrade warning. Fable's MSBuildCrackerResolver treats NU1605 as a fatal error, crashing before compilation begins.

Fix applied: Bumped Microsoft.Bcl.AsyncInterfaces from 10.0.510.0.6 in FSharp.Control.AsyncSeq.fsproj. All 414 .NET tests still pass.

Note: this is a pre-existing issue unrelated to the mapAsyncParallelThrottled feature — it would have affected the main branch too once System.Threading.Channels 10.0.6 was released.

Generated by 🌈 Repo Assist, see workflow run. Learn more.

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@11c9a2c442e519ff2b427bf58679f5a525353f76

@dsyme dsyme marked this pull request as ready for review April 17, 2026 10:24
@dsyme dsyme merged commit fc443a8 into main Apr 17, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant