perf: parallelize post-resolution event invocation#4676
Conversation
Replace sequential foreach+await with Parallel.ForEachAsync for InvokePostResolutionEventsAsync. Per-test events are independent, so for large test suites (thousands of tests) this eliminates a major sequential bottleneck during discovery. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Code reviewNo issues found. Checked for bugs and CLAUDE.md compliance. Architecture & Design ObservationsThis is a well-implemented performance optimization that follows good engineering practices. The change is clean, safe, and appropriately scoped. A few observations on the design: Strengths:
Architectural consideration (optional future enhancement): The // Example: using SemaphoreSlim for bounded concurrency on pre-.NET 6
var maxConcurrency = Environment.ProcessorCount;
using var semaphore = new SemaphoreSlim(maxConcurrency);
var tasks = allTests.Select(async test =>
{
await semaphore.WaitAsync().ConfigureAwait(false);
try
{
await _testBuilderPipeline.InvokePostResolutionEventsAsync(test).ConfigureAwait(false);
}
finally
{
semaphore.Release();
}
});
await Task.WhenAll(tasks).ConfigureAwait(false);However, this adds complexity and allocations, so it's only worth considering if profiling shows resource contention on legacy frameworks with very large test suites. The current implementation prioritizes simplicity, which is the right trade-off for now. Why this matters: Performance optimizations should balance throughput gains against resource consumption. The current approach maximizes throughput on legacy frameworks at the cost of potentially unbounded concurrency. For the typical TUnit workload (post-resolution events are likely fast), this is fine. But if events become more resource-intensive (e.g., network calls, heavy I/O), bounded concurrency becomes more important. Overall, this is solid work that meaningfully improves test discovery performance while maintaining code quality and safety. |
Summary
foreach+awaitwithParallel.ForEachAsyncforInvokePostResolutionEventsAsyncduring test discoveryParallelThresholds.MinItemsForParallel) to avoid parallelization overhead for small test countsTask.WhenAllon pre-.NET 6 targetsTest plan
🤖 Generated with Claude Code