static bool GetRulesTodo(ParallelExecutionContext parallelContext, bool returnTrueOnlyIfNewParallelRulesFound = false) { var newAvailableRules = parallelContext.ExecutionContext .GetRulesWhichMayBeExecuted() .Except(parallelContext.ParallelTodo) .Except(parallelContext.NonParallelTodo) .ToList(); if (!newAvailableRules.Any()) { return(false); } foreach (var rule in newAvailableRules.Where(x => x.IsEligibleToBeExecutedInParallel)) { parallelContext.ParallelTodo.Add(rule); } foreach (var rule in newAvailableRules.Where(x => !x.IsEligibleToBeExecutedInParallel)) { parallelContext.NonParallelTodo.Add(rule); } return(parallelContext.ParallelTodo.Any() || !returnTrueOnlyIfNewParallelRulesFound); }
/// <inheritdoc/> public async Task <IReadOnlyCollection <ValidationRuleResult> > ExecuteAllRulesAsync(IRuleExecutionContext executionContext, CancellationToken cancellationToken = default) { var parallelContext = new ParallelExecutionContext(executionContext); var results = new List <ValidationRuleResult>(); // See the XML 'remarks' comments on the class for a description of this algorithm. while (GetRulesTodo(parallelContext)) { var parallelResults = await ExecuteAsManyParallelRulesAsPossibleAsync(parallelContext, cancellationToken).ConfigureAwait(false); results.AddRange(parallelResults); var nonParallelResults = await RuleExecutor.ExecuteRulesAsync(parallelContext.NonParallelTodo, ruleExecutor, parallelContext.ExecutionContext, cancellationToken).ConfigureAwait(false); results.AddRange(nonParallelResults); parallelContext.NonParallelTodo.Clear(); } return(results); }
async Task <IEnumerable <ValidationRuleResult> > ExecuteAsManyParallelRulesAsPossibleAsync(ParallelExecutionContext parallelContext, CancellationToken cancellationToken) { var results = new List <ValidationRuleResult>(); do { var rulesInProgress = parallelContext.ParallelTodo .Select(rule => RuleExecutor.ExecuteRuleAsync(rule, ruleExecutor, parallelContext.ExecutionContext, cancellationToken)) .ToList(); parallelContext.ParallelTodo.Clear(); while (rulesInProgress.Any()) { var resultTask = await Task.WhenAny(rulesInProgress).ConfigureAwait(false); rulesInProgress.Remove(resultTask); var result = await resultTask.ConfigureAwait(false); results.Add(result); cancellationToken.ThrowIfCancellationRequested(); } } while (GetRulesTodo(parallelContext, returnTrueOnlyIfNewParallelRulesFound: true)); return(results); }