J'essaie de créer une application de console asynchrone qui effectue un peu de travail sur une collection. J'ai une version qui utilise parallèle pour boucler une autre version qui utilise async/wait. Je m'attendais à ce que la version async/wait fonctionne de manière similaire à la version parallèle, mais elle s'exécute de manière synchrone. Qu'est-ce que je fais mal?
class Program
{
static void Main(string[] args)
{
var worker = new Worker();
worker.ParallelInit();
var t = worker.Init();
t.Wait();
Console.ReadKey();
}
}
public class Worker
{
public async Task<bool> Init()
{
var series = Enumerable.Range(1, 5).ToList();
foreach (var i in series)
{
Console.WriteLine("Starting Process {0}", i);
var result = await DoWorkAsync(i);
if (result)
{
Console.WriteLine("Ending Process {0}", i);
}
}
return true;
}
public async Task<bool> DoWorkAsync(int i)
{
Console.WriteLine("working..{0}", i);
await Task.Delay(1000);
return true;
}
public bool ParallelInit()
{
var series = Enumerable.Range(1, 5).ToList();
Parallel.ForEach(series, i =>
{
Console.WriteLine("Starting Process {0}", i);
DoWorkAsync(i);
Console.WriteLine("Ending Process {0}", i);
});
return true;
}
}
La façon dont vous utilisez le mot clé await
indique à C # que vous souhaitez attendre à chaque fois que vous passez dans la boucle, qui n'est pas parallèle. Vous pouvez réécrire votre méthode comme celle-ci pour faire ce que vous voulez, en stockant une liste de Task
s, puis de await
les tous avec Task.WhenAll
.
public async Task<bool> Init()
{
var series = Enumerable.Range(1, 5).ToList();
var tasks = new List<Task<Tuple<int, bool>>>();
foreach (var i in series)
{
Console.WriteLine("Starting Process {0}", i);
tasks.Add(DoWorkAsync(i));
}
foreach (var task in await Task.WhenAll(tasks))
{
if (task.Item2)
{
Console.WriteLine("Ending Process {0}", task.Item1);
}
}
return true;
}
public async Task<Tuple<int, bool>> DoWorkAsync(int i)
{
Console.WriteLine("working..{0}", i);
await Task.Delay(1000);
return Tuple.Create(i, true);
}
Votre code attend que chaque opération (en utilisant await
) se termine avant de commencer l'itération suivante.
Par conséquent, vous n’obtenez aucun parallélisme.
Si vous souhaitez exécuter une opération asynchrone existante en parallèle, vous n'avez pas besoin de await
; il vous suffit d'obtenir une collection de Task
s et d'appeler Task.WhenAll()
pour renvoyer une tâche qui les attend toutes:
return Task.WhenAll(list.Select(DoWorkAsync));
public async Task<bool> Init()
{
var series = Enumerable.Range(1, 5);
Task.WhenAll(series.Select(i => DoWorkAsync(i)));
return true;
}