Saya tidak begitu mengerti perbedaan antara Task.Wait
dan await
.
Saya memiliki sesuatu yang mirip dengan fungsi-fungsi berikut dalam layanan ASP.NET WebAPI:
public class TestController : ApiController
{
public static async Task<string> Foo()
{
await Task.Delay(1).ConfigureAwait(false);
return "";
}
public async static Task<string> Bar()
{
return await Foo();
}
public async static Task<string> Ros()
{
return await Bar();
}
// GET api/test
public IEnumerable<string> Get()
{
Task.WaitAll(Enumerable.Range(0, 10).Select(x => Ros()).ToArray());
return new string[] { "value1", "value2" }; // This will never execute
}
}
Dimana Get
akan menemui jalan buntu.
Apa yang bisa menyebabkan ini? Mengapa ini tidak menyebabkan masalah ketika saya menggunakan menunggu menunggu alih-alih await Task.Delay
?
Task.Delay(1).Wait()
pada dasarnya sama persis dengan Thread.Sleep(1000)
. Dalam kode produksi aktual, ini jarang sesuai.
WaitAll
menyebabkan kebuntuan. Lihat tautan ke blog saya di jawaban saya untuk lebih jelasnya. Anda harus menggunakannya await Task.WhenAll
sebagai gantinya.
ConfigureAwait(false)
sebuah tunggal panggilan untuk Bar
atau Ros
tidak akan deadlock, tetapi karena Anda memiliki enumerable yang menciptakan lebih dari satu dan kemudian menunggu semua orang, bar pertama akan kebuntuan kedua. Jika Anda await Task.WhenAll
alih-alih menunggu semua tugas, sehingga Anda tidak memblokir konteks ASP, Anda akan melihat metode kembali secara normal.
.ConfigureAwait(false)
semua jalan di atas pohon sampai Anda memblokir, dengan cara itu tidak ada yang pernah mencoba untuk kembali ke konteks utama; itu akan berhasil. Pilihan lain adalah memutar konteks sinkronisasi dalam. Link . Jika Anda menempatkan Task.WhenAll
dalam AsyncPump.Run
secara efektif akan memblokir di seluruh hal tanpa Anda perlu untuk ConfigureAwait
di mana saja, tapi itu mungkin solusi yang terlalu kompleks.
Task.Delay(1).Wait()
yang cukup baik.