beberapa menunggu vs Task.WaitAll - setara?

Aug 20 2015

Dalam hal kinerja, akan 2 metode ini berjalan GetAllWidgets()dan GetAllFoos()secara paralel?

Apakah ada alasan untuk menggunakan salah satunya? Sepertinya ada banyak hal yang terjadi di balik layar dengan kompiler jadi saya tidak merasa jelas.

============= Metode A: Menggunakan beberapa menunggu ======================

public async Task<IHttpActionResult> MethodA()
{
    var customer = new Customer();

    customer.Widgets = await _widgetService.GetAllWidgets();
    customer.Foos = await _fooService.GetAllFoos();

    return Ok(customer);
}

=============== MethodB: Menggunakan Task.WaitAll =====================

public async Task<IHttpActionResult> MethodB()
{
    var customer = new Customer();

    var getAllWidgetsTask = _widgetService.GetAllWidgets();
    var getAllFoosTask = _fooService.GetAllFos();

    Task.WaitAll(new List[] {getAllWidgetsTask, getAllFoosTask});

    customer.Widgets = getAllWidgetsTask.Result;
    customer.Foos = getAllFoosTask.Result;

    return Ok(customer);
}

=====================================

Jawaban

108 i3arnon Aug 20 2015 at 20:28

Opsi pertama tidak akan menjalankan dua operasi secara bersamaan. Ini akan mengeksekusi yang pertama dan menunggu penyelesaiannya, dan baru kemudian yang kedua.

Opsi kedua akan mengeksekusi keduanya secara bersamaan tetapi akan menunggunya secara sinkron (mis. Saat memblokir utas).

Anda tidak boleh menggunakan kedua opsi karena yang pertama selesai lebih lambat dari yang kedua dan yang kedua memblokir utas tanpa perlu.

Anda harus menunggu kedua operasi secara asinkron dengan Task.WhenAll:

public async Task<IHttpActionResult> MethodB()
{
    var customer = new Customer();

    var getAllWidgetsTask = _widgetService.GetAllWidgets();
    var getAllFoosTask = _fooService.GetAllFos();

    await Task.WhenAll(getAllWidgetsTask, getAllFoosTask);

    customer.Widgets = await getAllWidgetsTask;
    customer.Foos = await getAllFoosTask;

    return Ok(customer);
}

Perhatikan bahwa setelah Task.WhenAllselesai kedua tugas sudah selesai jadi menunggu mereka segera selesai.

18 Nitram Aug 20 2015 at 20:34

Jawaban singkatnya: Tidak.

Task.WaitAllmemblokir, awaitmengembalikan tugas segera setelah ditemukan dan mendaftarkan bagian yang tersisa dari fungsi dan kelanjutan.

Metode menunggu "massal" yang Anda cari adalah Task.WhenAllyang benar-benar membuat yang baru Taskyang selesai ketika semua tugas yang diserahkan ke fungsi tersebut selesai.

Seperti: await Task.WhenAll({getAllWidgetsTask, getAllFoosTask});

Itu untuk masalah pemblokiran.

Juga fungsi pertama Anda tidak menjalankan kedua fungsi secara paralel. Agar ini berfungsi, awaitAnda harus menulis sesuatu seperti ini:

var widgetsTask = _widgetService.GetAllWidgets();
var foosTask = _fooService.GetAllWidgets();
customer.Widgets = await widgetsTask;
customer.Foos = await foosTask;

Ini akan membuat contoh pertama bertindak sangat mirip dengan Task.WhenAllmetode tersebut.

nvoigt Aug 20 2015 at 20:28

Hanya opsi kedua Anda yang akan menjalankannya secara paralel. Pertama Anda akan menunggu di setiap panggilan secara berurutan.

KasperHoldum Aug 20 2015 at 20:28

Segera setelah Anda menjalankan metode async, itu akan mulai dijalankan. Apakah itu akan dijalankan pada utas saat ini (dan dengan demikian berjalan secara sinkron) atau akan berjalan asinkron tidak mungkin untuk ditentukan.

Jadi, dalam contoh pertama Anda, metode pertama akan mulai berfungsi, tetapi kemudian Anda menghentikan aliran kode dengan await. Dan dengan demikian metode kedua tidak akan dipanggil sebelum yang pertama selesai dieksekusi.

Contoh kedua memanggil kedua metode tanpa menghentikan aliran dengan menunggu. Jadi mereka berpotensi berjalan secara paralel jika metodenya asynchronous.

pnizzle Jun 14 2020 at 17:19

Sebagai tambahan atas apa yang dikatakan @ i3arnon. Anda akan melihat bahwa ketika Anda menggunakan awaitAnda terpaksa harus mendeklarasikan metode melampirkan sebagai async, tetapi waitAllAnda tidak melakukannya. Itu akan memberi tahu Anda bahwa ada lebih dari apa yang dikatakan jawaban utama. Ini dia:

WaitAllakan memblokir hingga tugas yang diberikan selesai, ia tidak meneruskan kontrol kembali ke pemanggil saat tugas tersebut berjalan. Juga seperti yang disebutkan, tugas dijalankan asynchronous sendiri, bukan ke pemanggil.

Awaittidak akan memblokir utas pemanggil, namun akan menangguhkan eksekusi kode di bawahnya, tetapi saat tugas sedang berjalan, kontrol dikembalikan ke pemanggil. Untuk fakta bahwa kontrol dikembalikan kembali ke pemanggil (metode yang dipanggil menjalankan async), Anda harus menandai metode sebagai asinkron.

Semoga perbedaannya jelas. Bersulang