L'idée derrière Parallel.ForEach()
est que vous avez un ensemble de threads et que chaque thread traite une partie de la collection. Comme vous l'avez remarqué, cela ne fonctionne pas avec async
- await
, où vous souhaitez libérer le thread pour la durée de l'appel asynchrone.
Vous pouvez «corriger» cela en bloquant les ForEach()
threads, mais cela va à l'encontre de tout l'intérêt de async
- await
.
Ce que vous pouvez faire, c'est utiliser TPL Dataflow à la place de Parallel.ForEach()
, qui prend Task
bien en charge les s asynchrones .
Plus précisément, votre code peut être écrit en utilisant un TransformBlock
qui transforme chaque identifiant en un en Customer
utilisant le async
lambda. Ce bloc peut être configuré pour s'exécuter en parallèle. Vous lieriez ce bloc à un ActionBlock
qui écrit chacun Customer
sur la console. Après avoir configuré le réseau de blocage, vous pouvez Post()
chaque identifiant sur le TransformBlock
.
Dans du code:
var ids = new List<string> { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" };
var getCustomerBlock = new TransformBlock<string, Customer>(
async i =>
{
ICustomerRepo repo = new CustomerRepo();
return await repo.GetCustomer(i);
}, new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded
});
var writeCustomerBlock = new ActionBlock<Customer>(c => Console.WriteLine(c.ID));
getCustomerBlock.LinkTo(
writeCustomerBlock, new DataflowLinkOptions
{
PropagateCompletion = true
});
foreach (var id in ids)
getCustomerBlock.Post(id);
getCustomerBlock.Complete();
writeCustomerBlock.Completion.Wait();
Bien que vous souhaitiez probablement limiter le parallélisme du TransformBlock
à une petite constante. En outre, vous pouvez limiter la capacité du TransformBlock
et y ajouter les éléments de manière asynchrone en utilisant SendAsync()
, par exemple, si la collection est trop grande.
Un avantage supplémentaire par rapport à votre code (s'il a fonctionné) est que l'écriture commencera dès qu'un seul élément est terminé, et n'attendra pas que tout le traitement soit terminé.