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
refactor!: remove result-discarding InParallelAsync overloads and polish packaging (#373)
* refactor!: remove result-discarding InParallelAsync overloads and polish packaging
The Func<TSource, Task<TResult>> and Func<TSource, TResult> overloads
returned plain Task and silently dropped every result. Callers that
want results already have SelectAsync(...).ProcessInParallel(...);
result-returning delegates still bind to the surviving Func<TSource,
Task> and Action<TSource> overloads with identical behaviour.
Also: XML docs for ParallelExtensions and IAsyncProcessor, NuGet
package icon, refreshed package description covering IAsyncEnumerable
streaming and timed rate limiting.
* docs: correct InParallelAsync migration and cancellation doc claims
Async value-returning lambdas and explicitly typed result delegates do
not bind to the surviving overloads, and item faults take precedence
over cancellation on the returned task.
<Description>Various Enumerable Async Processors - Batch / Parallel / Rate Limited / One at a time</Description>
22
+
<Description>Process async tasks over IEnumerable and IAsyncEnumerable sources with controlled concurrency: one at a time, batched, bounded parallel, timed rate limited (e.g. requests per second), or fully parallel. Fluent API with streaming results, exception fidelity, cancellation and disposal support.</Description>
/// <param name="source">The items to process. The sequence is materialized once before workers start.</param>
16
+
/// <param name="levelOfParallelism">Maximum concurrent operations. Zero or negative uses <see cref="Environment.ProcessorCount"/>.</param>
17
+
/// <param name="taskSelector">The async operation to perform on each item. Any result carried by a returned <c>Task<T></c> is not collected.</param>
18
+
/// <returns>
19
+
/// A task that completes when every item has been processed. When multiple items fail, awaiting it
20
+
/// throws the first failure while <c>Task.Exception.InnerExceptions</c> carries every failure.
21
+
/// </returns>
24
22
publicstaticTaskInParallelAsync<TSource>(
25
23
thisIEnumerable<TSource>source,
26
24
intlevelOfParallelism,
@@ -29,6 +27,18 @@ public static Task InParallelAsync<TSource>(
/// <param name="source">The items to process. The sequence is materialized once before workers start.</param>
35
+
/// <param name="levelOfParallelism">Maximum concurrent operations. Zero or negative uses <see cref="Environment.ProcessorCount"/>.</param>
36
+
/// <param name="taskSelector">The async operation to perform on each item. Any result carried by a returned <c>Task<T></c> is not collected.</param>
37
+
/// <param name="cancellationToken">Stops claiming new items when cancelled. The returned task then completes as canceled, unless items had already failed - their exceptions take precedence.</param>
38
+
/// <returns>
39
+
/// A task that completes when every item has been processed. When multiple items fail, awaiting it
40
+
/// throws the first failure while <c>Task.Exception.InnerExceptions</c> carries every failure.
41
+
/// </returns>
32
42
publicstaticTaskInParallelAsync<TSource>(
33
43
thisIEnumerable<TSource>source,
34
44
intlevelOfParallelism,
@@ -38,24 +48,18 @@ public static Task InParallelAsync<TSource>(
/// <param name="source">The items to process. The sequence is materialized once before workers start.</param>
56
+
/// <param name="levelOfParallelism">Maximum concurrent operations. Zero or negative uses <see cref="Environment.ProcessorCount"/>.</param>
57
+
/// <param name="taskSelector">The synchronous operation to perform on each item.</param>
58
+
/// <param name="cancellationToken">Stops claiming new items when cancelled. The returned task then completes as canceled, unless items had already failed - their exceptions take precedence.</param>
59
+
/// <returns>
60
+
/// A task that completes when every item has been processed. When multiple items fail, awaiting it
61
+
/// throws the first failure while <c>Task.Exception.InnerExceptions</c> carries every failure.
Copy file name to clipboardExpand all lines: README.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -35,7 +35,8 @@ Version 4 is a major release. Review these source and behaviour changes before u
35
35
-**Arbitrary upper limits were removed.** Task counts and batch sizes may exceed 10,000, and time windows may exceed 24 hours. Validity checks remain: counts, batch sizes, concurrency, and permit counts must be positive; time windows cannot be negative.
36
36
-**Validation is consistent and eager.** Invalid `maxConcurrency`, parallelism, batch, and timed-rate arguments now throw while the processor is built for both action and result variants.
37
37
-**`TaskWrapper` types and processor plumbing are internal.** The `ActionTaskWrapper`/`ItemTaskWrapper` structs and the previously `protected` members of the abstract processor base classes (`TaskWrappers`, `EnumerableTaskCompletionSources`, `CancellationToken`, constructors) were implementation details that could not be meaningfully used outside the library, and are no longer public.
38
-
-**Synchronous `InParallelAsync` delegates now run concurrently.** The `Func<TSource, TResult>` and `Action<TSource>` overloads use thread-pool workers instead of executing delegates sequentially on the caller. Do not depend on their previous thread affinity or execution order.
38
+
-**Synchronous `InParallelAsync` delegates now run concurrently.** The `Action<TSource>` overload uses thread-pool workers instead of executing delegates sequentially on the caller. Do not depend on its previous thread affinity or execution order.
39
+
-**The result-selector `InParallelAsync` overloads were removed.** The `Func<TSource, Task<TResult>>` and `Func<TSource, TResult>` overloads returned a plain `Task` and silently discarded every result. Use `SelectAsync(...).ProcessInParallel(...)` to collect results. Fire-and-await callers can keep non-async lambdas returning `Task<T>` (they bind to the `Func<TSource, Task>` overload), but async lambdas that return a value and explicitly typed result-returning delegates must be rewritten to discard the result (e.g. `async x => { _ = await GetAsync(x); }`).
39
40
-**An already-cancelled token yields cancelled tasks, not `ArgumentException`.** Building a processor with a token that is already cancelled (or that cancels between building and the terminal call) now produces a processor whose per-item tasks are cancelled; `WaitAsync`/`GetResultsAsync` throw `OperationCanceledException`. Previously this threw `ArgumentException` from an internal constructor.
40
41
-**`IAsyncEnumerable<T>` processors preserve every failure.** The `Task` returned by `ExecuteAsync()` now carries all failures via `Task.Exception.InnerExceptions` (awaiting still throws the first), matching the `IEnumerable<T>` processors. Previously only the first failure was observable and the rest were lost.
41
42
-**`ExecuteAsync()` enforces single use.** Calling it a second time throws `InvalidOperationException`; calling it after disposal throws `ObjectDisposedException`. Previously a second call failed with a confusing `ObjectDisposedException` from internal plumbing.
0 commit comments