web-dev-qa-db-fra.com

Comment écrire correctement Parallel.For avec des méthodes asynchrones

Comment structurer le code ci-dessous pour que la méthode async soit invoquée?

Parallel.For(0, elevations.Count(), delegate(int i)
{
   allSheets.AddRange(await BuildSheetsAsync(userID, elevations[i], includeLabels));
});

Parallel.For() ne fonctionne pas bien avec les méthodes async. Si vous n'avez pas besoin de limiter le degré de parallélisme (c'est-à-dire que vous êtes d'accord avec toutes les tâches s'exécutant en même temps), vous pouvez simplement démarrer toutes les Tasks et attendre qu'elles se terminent:

var tasks = Enumerable.Range(0, elevations.Count())
    .Select(i => BuildSheetsAsync(userID, elevations[i], includeLabels));
List<Bitmap> allSheets = (await Task.WhenAll(tasks)).SelectMany(x => x).ToList();
37
svick

Je vous recommande de jeter un œil à cette question que j'ai posée il y a quelques jours et qui a fini par me répondre, je cherchais essentiellement une méthode ForEach parallèle et asynchrone .

La méthode utilise SemaphoreSlim pour traiter les choses en parallèle et elle accepte les méthodes asynchrones comme action d'entrée.

Vous voudrez peut-être également jeter un coup d'œil aux deux liens que j'ai fournis à la fin de ma réponse, ils ont été vraiment utiles pour réaliser un tel comportement et ils contiennent également une autre façon de le faire en utilisant un Partitioner à la place.

Personnellement, je n'ai pas aimé le Parallel.For parce que c'est un appel synchrone comme expliqué dans les liens que j'ai donnés; Je voulais tout 'async' :-)

Le voici: Téléchargement asynchrone et parallèle de fichiers

4
Aybe

Vous pouvez essayer ce code que j'utilise. il en utilisant foreach et SemaphoreSlim pour obtenir parallèle asynchrone.

public static class ParallelAsync
{
    public static async Task ForeachAsync<T>(IEnumerable<T> source, int maxParallelCount, Func<T, Task> action)
    {
        using (SemaphoreSlim completeSemphoreSlim = new SemaphoreSlim(1))
        using (SemaphoreSlim taskCountLimitsemaphoreSlim = new SemaphoreSlim(maxParallelCount))
        {
            await completeSemphoreSlim.WaitAsync();
            int runningtaskCount = source.Count();

            foreach (var item in source)
            {
                await taskCountLimitsemaphoreSlim.WaitAsync();

                Task.Run(async () =>
                {
                    try
                    {
                        await action(item).ContinueWith(task =>
                        {
                            Interlocked.Decrement(ref runningtaskCount);
                            if (runningtaskCount == 0)
                            {
                                completeSemphoreSlim.Release();
                            }
                        });
                    }
                    finally
                    {
                        taskCountLimitsemaphoreSlim.Release();
                    }
                }).GetHashCode();
            }

            await completeSemphoreSlim.WaitAsync();
        }
    }
}

usage:

string[] a = new string[] {
    "1",
    "2",
    "3",
    "4",
    "5",
    "6",
    "7",
    "8",
    "9",
    "10",
    "11",
    "12",
    "13",
    "14",
    "15",
    "16",
    "17",
    "18",
    "19",
    "20"
};

Random random = new Random();

await ParallelAsync.ForeachAsync(a, 2, async item =>
{
    Console.WriteLine(item + " start");

    await Task.Delay(random.Next(1500, 3000));
    Console.WriteLine(item + " end");
});

Console.WriteLine("All finished");

toute suggestion s'il vous plaît faites le moi savoir.

0
Alex Zhang