235 votes

Foreach parallèle avec lambda asynchrone

Je voudrais gérer une collection en parallèle, mais j'ai du mal à le mettre en œuvre et j'espère donc avoir de l'aide.

Le problème se pose si je veux appeler une méthode marquée async en C#, à l'intérieur du lambda de la boucle parallèle. Par exemple :

var bag = new ConcurrentBag<object>();
Parallel.ForEach(myCollection, async item =>
{
  // some pre stuff
  var response = await GetData(item);
  bag.Add(response);
  // some post stuff
}
var count = bag.Count;

Le problème se pose lorsque le nombre est égal à 0, car tous les threads créés ne sont en fait que des threads d'arrière-plan et l'option Parallel.ForEach L'appel n'attend pas l'achèvement. Si je supprime le mot clé async, la méthode ressemble à ceci :

var bag = new ConcurrentBag<object>();
Parallel.ForEach(myCollection, item =>
{
  // some pre stuff
  var responseTask = await GetData(item);
  responseTask.Wait();
  var response = responseTask.Result;
  bag.Add(response);
  // some post stuff
}
var count = bag.Count;

Cela fonctionne, mais cela désactive complètement l'intelligence d'attente et je dois faire un peu de gestion manuelle des exceptions (Supprimé pour des raisons de brièveté).

Comment puis-je mettre en œuvre un Parallel.ForEach qui utilise le mot clé await dans la boucle lambda ? Est-ce possible ?

Le prototype de la méthode Parallel.ForEach prend un Action<T> comme paramètre, mais je veux qu'il attende mon lambda asynchrone.

-2voto

Gravity API Points 393

Pour une solution plus simple (pas sûr que ce soit la plus optimale), vous pouvez simplement imbriquer les éléments suivants Parallel.ForEach à l'intérieur d'un Task - comme tel

var options = new ParallelOptions { MaxDegreeOfParallelism = 5 }
Task.Run(() =>
{
    Parallel.ForEach(myCollection, options, item =>
    {
        DoWork(item);
    }
}

Le site ParallelOptions fera l'étranglement pour vous, en sortant de la boîte.

Je l'utilise dans un scénario réel pour exécuter des opérations très longues en arrière-plan. Ces opérations sont appelées via HTTP et il a été conçu pour ne pas bloquer l'appel HTTP pendant l'exécution de l'opération longue.

  1. Appel à HTTP pour une longue opération en arrière-plan.
  2. L'opération commence à l'arrière-plan.
  3. L'utilisateur obtient un ID d'état qui peut être utilisé pour vérifier l'état en utilisant un autre appel HTTP.
  4. L'opération en arrière-plan met à jour son statut.

De cette façon, l'appel CI/CD n'est pas interrompu à cause d'une longue opération HTTP, mais il boucle l'état toutes les x secondes sans bloquer le processus.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X