Я пытаюсь создать асинхронное консольное приложение, которое выполняет некоторую работу с коллекцией. У меня есть одна версия, которая использует параллельный цикл для другой версии, которая использует async / await. Я ожидал, что версия async / await будет работать аналогично параллельной версии, но выполняется синхронно. Что я делаю не так?
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;
}
}
c#
.net
async-await
Satish
источник
источник
Ending Process
уведомление, это не означает, что задача действительно заканчивается. Все эти уведомления выгружаются последовательно сразу после завершения последней задачи. К тому времени, когда вы увидите «Ending Process 1», процесс 1, возможно, уже давно закончился. Кроме выбора слов там +1.Semaphore
inDoWorkAsync
для ограничения максимального числа выполняемых задач?Ваш код ожидает
await
завершения каждой операции (использования ) перед началом следующей итерации.Следовательно, никакого параллелизма не будет.
Если вы хотите запустить существующую асинхронную операцию параллельно, вам не нужно
await
; вам просто нужно получить коллекциюTask
s и вызватьTask.WhenAll()
задачу, которая ожидает их всех:return Task.WhenAll(list.Select(DoWorkAsync));
источник
await
делает прямо противоположное тому, что вы хотите - это ждет дляTask
закончить.DoWorkAsync
для каждого элементаlist
(передавая каждый элементDoWorkAsync
, который, как я полагаю, имеет один параметр)?public async Task<bool> Init() { var series = Enumerable.Range(1, 5); Task.WhenAll(series.Select(i => DoWorkAsync(i))); return true; }
источник
В C # 7.0 вы можете использовать семантические имена для каждого из членов кортежа , вот ответ Тима С. с использованием нового синтаксиса:
public async Task<bool> Init() { var series = Enumerable.Range(1, 5).ToList(); var tasks = new List<Task<(int Index, bool IsDone)>>(); 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.IsDone) { Console.WriteLine("Ending Process {0}", task.Index); } } return true; } public async Task<(int Index, bool IsDone)> DoWorkAsync(int i) { Console.WriteLine("working..{0}", i); await Task.Delay(1000); return (i, true); }
Вы также могли бы избавиться от
task.
внутреннегоforeach
:// ... foreach (var (IsDone, Index) in await Task.WhenAll(tasks)) { if (IsDone) { Console.WriteLine("Ending Process {0}", Index); } } // ...
источник