Apakah menggunakan pernyataan dan menunggu kata kunci bermain dengan baik di c #

101

Saya mengalami situasi di mana saya melakukan asyncpanggilan ke metode yang mengembalikan dan IDisposablecontoh. Sebagai contoh:

HttpResponseMessage response = await httpClient.GetAsync(new Uri("http://www.google.com"));

Sekarang sebelumnya asyncada di tempat kejadian, ketika bekerja dengan sebuah IDisposableinstance, panggilan dan kode ini yang menggunakan variabel "respon" akan dibungkus dalam pernyataan menggunakan.

Pertanyaan saya adalah apakah itu masih merupakan pendekatan yang benar ketika asynckata kunci dimasukkan ke dalam campuran? Meskipun kode dikompilasi, akankah pernyataan using tetap berfungsi seperti yang diharapkan pada kedua contoh di bawah?

Contoh 1

using(HttpResponseMessage response = await httpClient.GetAsync(new Uri("http://www.google.com")))
{
    // Do something with the response

    return true;
}

Contoh 2

using(HttpResponseMessage response = await httpClient.GetAsync(new Uri("http://www.google.com")))
{
    await this.responseLogger.LogResponseAsync(response);

    return true;
}
swingdoctor
sumber

Jawaban:

97

Ya, itu tidak masalah.

Dalam kasus pertama, Anda benar-benar mengatakan:

  • Tunggu secara tidak bersamaan hingga kami mendapatkan respons
  • Gunakan dan segera buang

Dalam kasus kedua, Anda mengatakan:

  • Tunggu secara tidak bersamaan hingga kami mendapatkan respons
  • Tunggu secara tidak bersamaan hingga kami mencatat responsnya
  • Buang tanggapannya

Sebuah usingpernyataan di metode async adalah "aneh" di bahwa Disposepanggilan dapat mengeksekusi dalam thread yang berbeda dengan yang yang diperoleh sumber daya (tergantung pada sinkronisasi konteks dll) tapi masih akan terjadi ... dengan asumsi hal yang Anda tunggu sedang untuk pernah muncul atau gagal, tentu saja. (Sama seperti Anda tidak akan akhirnya memanggil Disposekode non-asinkron jika usingpernyataan Anda berisi panggilan ke metode yang tidak pernah kembali.)

Jon Skeet
sumber
4
Terima kasih Jon. Meskipun sebagian besar hal asinkron masih bersifat voodoo bagi saya, cukup meyakinkan untuk melihat seberapa sering hal itu terintegrasi dengan fitur .net lainnya dan berfungsi
swingdoctor
@JonSkeet Haruskah menunggu bahkan digunakan di dalam using(){...}blok atau itu berlebihan atau dapat menurunkan kinerja dalam beberapa kasus? Apakah using(){...}melayani tujuan yang sama seperti await?
nam
1
@ nam: Tidak, usingdan awaitmelayani tujuan yang sepenuhnya berbeda. Perhatikan bahwa C # 8 sekarang memiliki pembuangan asinkron juga. Meskipun penting untuk menyadari masalah threading, jawaban saya menyoroti, itu pasti tidak berarti salah untuk mencampur usingdan await.
Jon Skeet