Saya mencoba membuat aplikasi konsol asinkron yang melakukan beberapa pekerjaan pada koleksi. Saya memiliki satu versi yang menggunakan paralel for loop versi lain yang menggunakan async / await. Saya mengharapkan versi async / await berfungsi mirip dengan versi paralel tetapi dijalankan secara sinkron. Apa yang saya lakukan salah?
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
sumber
sumber
Ending Process
notifikasi bukan saat tugas benar-benar berakhir. Semua pemberitahuan tersebut dibuang secara berurutan tepat setelah tugas terakhir selesai. Pada saat Anda melihat "Mengakhiri Proses 1", proses 1 mungkin sudah lama berakhir. Selain pilihan kata yang ada, +1.Semaphore
inDoWorkAsync
untuk membatasi tugas eksekusi maksimum?Kode Anda menunggu untuk setiap operasi (menggunakan
await
) selesai sebelum memulai iterasi berikutnya.Oleh karena itu, Anda tidak mendapatkan paralelisme apa pun.
Jika Anda ingin menjalankan operasi asinkron yang ada secara paralel, Anda tidak perlu
await
; Anda hanya perlu mendapatkan sekumpulanTask
s dan panggilanTask.WhenAll()
untuk mengembalikan tugas yang menunggu semuanya:return Task.WhenAll(list.Select(DoWorkAsync));
sumber
await
tidak sebaliknya dari apa yang Anda inginkan - itu menunggu untukTask
selesai.DoWorkAsync
pada setiap item masuklist
(meneruskan setiap itemDoWorkAsync
, yang saya asumsikan memiliki parameter tunggal)?public async Task<bool> Init() { var series = Enumerable.Range(1, 5); Task.WhenAll(series.Select(i => DoWorkAsync(i))); return true; }
sumber
Di C # 7.0 Anda dapat menggunakan nama semantik untuk setiap anggota tupel , berikut adalah jawaban Tim S. menggunakan sintaks baru:
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); }
Anda juga bisa menyingkirkan bagian
task.
dalamforeach
:// ... foreach (var (IsDone, Index) in await Task.WhenAll(tasks)) { if (IsDone) { Console.WriteLine("Ending Process {0}", Index); } } // ...
sumber