Saya memiliki async
metode yang tidak mengembalikan data:
public async Task MyAsyncMethod()
{
// do some stuff async, don't return any data
}
Saya memanggil ini dari metode lain yang mengembalikan beberapa data:
public string GetStringData()
{
MyAsyncMethod(); // this generates a warning and swallows exceptions
return "hello world";
}
Memanggil MyAsyncMethod()
tanpa menunggu menyebabkan " Karena panggilan ini tidak ditunggu, metode saat ini terus berjalan sebelum panggilan selesai " peringatan di studio visual. Pada halaman peringatan itu disebutkan:
Anda harus mempertimbangkan untuk menekan peringatan hanya jika Anda yakin tidak ingin menunggu panggilan tidak sinkron selesai dan bahwa metode yang dipanggil tidak akan memunculkan pengecualian .
Saya yakin saya tidak ingin menunggu sampai panggilan selesai; Saya tidak perlu atau punya waktu untuk itu. Tapi panggilan itu bisa menimbulkan pengecualian.
Saya telah menemukan masalah ini beberapa kali dan saya yakin itu adalah masalah umum yang harus memiliki solusi bersama.
Bagaimana saya memanggil metode async dengan aman tanpa menunggu hasilnya?
Memperbarui:
Bagi orang yang menyarankan agar saya menunggu hasilnya, ini adalah kode yang merespons permintaan web pada layanan web kami (ASP.NET Web API). Menunggu dalam konteks UI membuat utas UI tetap bebas, tetapi menunggu dalam panggilan permintaan web akan menunggu Tugas selesai sebelum menanggapi permintaan, sehingga meningkatkan waktu respons tanpa alasan.
sumber
MyAsyncMethod().Wait()
Jawaban:
Jika Anda ingin mendapatkan pengecualian "asinkron", Anda dapat melakukan:
Ini akan memungkinkan Anda untuk menangani pengecualian pada utas selain utas "utama". Ini berarti Anda tidak perlu "menunggu" untuk panggilan
MyAsyncMethod()
dari utas yang memanggilMyAsyncMethod
; tetapi, masih memungkinkan Anda untuk melakukan sesuatu dengan pengecualian - tetapi hanya jika pengecualian terjadi.Memperbarui:
secara teknis, Anda dapat melakukan sesuatu yang mirip dengan
await
:... yang akan berguna jika Anda perlu secara khusus menggunakan
try
/catch
(atauusing
) tetapi saya menemukanContinueWith
untuk menjadi sedikit lebih eksplisit karena Anda harus tahu apaConfigureAwait(false)
artinya.sumber
Task
: public static class AsyncUtility {public static void PerformAsyncTaskWithoutAwait (tugas Tugas ini, Aksi <Task> exceptionHandler) {var dummy = task.ContinueWith (t => exceptionHandler (t), TaskContinuationOptions.OnlyOnFaulted); }} Penggunaan: MyAsyncMethod (). PerformAsyncTaskWithoutAwait (t => log.ErrorFormat ("Terjadi kesalahan saat memanggil MyAsyncMethod: \ n {0}", t.Exception));ConfiguratAwait(false)
tidak dieksekusi sampai tugas selesai, tetapi utas saat ini tidak "menunggu" (yaitu blok) untuk itu, baris berikutnya dipanggil secara tidak serempak ke doa menunggu. TanpaConfigureAwait(false)
baris berikutnya akan dieksekusi pada konteks permintaan web asli. DenganConfigurateAwait(false)
itu dieksekusi dalam konteks yang sama dengan metode async (tugas), membebaskan konteks / utas asli untuk melanjutkan ...Pertama-tama Anda harus mempertimbangkan membuat
GetStringData
suatuasync
metode danawait
mengembalikannya dari tugasMyAsyncMethod
.Jika Anda benar-benar yakin bahwa Anda tidak perlu menangani pengecualian dari
MyAsyncMethod
atau tahu kapan itu selesai, maka Anda dapat melakukan ini:BTW, ini bukan "masalah umum". Sangat jarang ingin mengeksekusi beberapa kode dan tidak peduli apakah itu selesai dan tidak peduli apakah itu berhasil diselesaikan.
Memperbarui:
Karena Anda menggunakan ASP.NET dan ingin kembali lebih awal, Anda mungkin menemukan posting blog saya pada subjek yang bermanfaat . Namun, ASP.NET tidak dirancang untuk ini, dan tidak ada jaminan bahwa kode Anda akan berjalan setelah respons dikembalikan. ASP.NET akan melakukan yang terbaik untuk menjalankannya, tetapi tidak dapat menjaminnya.
Jadi, ini adalah solusi yang baik untuk sesuatu yang sederhana seperti melempar sebuah acara ke log di mana itu tidak benar-benar peduli jika Anda kehilangan beberapa di sana-sini. Ini bukan solusi yang baik untuk segala jenis operasi bisnis-kritis. Dalam situasi itu, Anda harus mengadopsi arsitektur yang lebih kompleks, dengan cara yang gigih untuk menyelamatkan operasi (misalnya, Antrian Azure, MSMQ) dan proses latar belakang yang terpisah (misalnya, Peran Pekerja Azure, Layanan Win32) untuk memprosesnya.
sumber
var _ = MyAsyncMethod();
dengan_ = MyAsyncMethod();
. Ini masih menghindari CS4014 peringatan, tetapi membuatnya sedikit lebih eksplisit bahwa Anda tidak menggunakan variabel.Jawaban oleh Peter Ritchie adalah apa yang saya inginkan, dan artikel Stephen Cleary tentang kembali lebih awal di ASP.NET sangat membantu.
Namun, sebagai masalah yang lebih umum (tidak spesifik untuk konteks ASP.NET) aplikasi Konsol berikut menunjukkan penggunaan dan perilaku jawaban Peter menggunakan
Task.ContinueWith(...)
GetStringData()
kembali lebih awal tanpa menungguMyAsyncMethod()
dan pengecualian yang dilemparkanMyAsyncMethod()
ditangani dalamOnMyAsyncMethodFailed(Task task)
dan bukan ditry
/catch
sekitarGetStringData()
sumber
Console.ReadLine();
dan tambahkan sedikit tidur / keterlambatanMyAsyncMethod
dan Anda tidak akan pernah melihat pengecualian.Saya berakhir dengan solusi ini:
sumber
Ini disebut api dan lupakan, dan ada perpanjangan untuk itu.
Instal paket nuget .
Menggunakan:
sumber
Saya kira timbul pertanyaan, mengapa Anda perlu melakukan ini? Alasan
async
dalam C # 5.0 adalah agar Anda dapat menunggu hasilnya. Metode ini sebenarnya tidak asinkron, tetapi hanya dipanggil pada suatu waktu agar tidak terlalu mengganggu thread saat ini.Mungkin lebih baik memulai utas dan membiarkannya selesai sendiri.
sumber
async
sedikit lebih dari sekadar "menunggu" hasilnya. "menunggu" menyiratkan bahwa garis-garis yang mengikuti "menunggu" dieksekusi secara asinkron pada utas yang sama yang memanggil "menunggu". Ini bisa dilakukan tanpa "menunggu", tentu saja, tetapi Anda akhirnya memiliki banyak delegasi dan kehilangan tampilan dan rasa kode yang berurutan (serta kemampuan untuk menggunakanusing
dantry/catch
...await
kata kunci, dan tidak menggunakanasync
kata kunci, tetapi tidak ada gunanya menggunakanasync
kata kunci tanpa juga menggunakanawait
definisi metode itu.async
sedikit lebih dari sekadar" menunggu "hasilnya." Kataasync
kunci (Anda menyiratkan kata kunci dengan melampirkannya di backticks) berarti tidak lebih dari menunggu hasilnya. Ini tidak sinkron, seperti konsep CS umum, itu berarti lebih dari sekadar menunggu hasil.async
menciptakan mesin status yang mengelola semua menunggu dalam metode async. Jika tidak adaawait
s dalam metode itu masih menciptakan mesin negara itu - tetapi metode ini tidak sinkron. Dan jikaasync
metode ini kembalivoid
, tidak ada yang menunggu. Jadi, ini lebih dari sekedar menunggu hasil.async
kata kunci. Yang perlu Anda lakukan (dan semua yang benar-benar terjadi pada akhirnya dengan mesin negara dalam kasus khusus) adalah bahwa metode ini dijalankan secara sinkron dan kemudian dibungkus dengan tugas yang selesai. Saya kira secara teknis Anda tidak hanya menghapus mesin negara; Anda menghapus mesin negara dan kemudian meneleponTask.FromResult
. Saya berasumsi Anda (dan juga penulis kompiler) dapat menambahkan addendum sendiri.Pada teknologi dengan loop pesan (tidak yakin apakah ASP adalah salah satunya), Anda dapat memblokir loop dan memproses pesan sampai tugas selesai, dan menggunakan ContinueWith untuk membuka blokir kode:
Pendekatan ini mirip dengan pemblokiran pada ShowDialog dan tetap menjaga UI responsif.
sumber
Saya terlambat ke pesta di sini, tapi ada perpustakaan luar biasa yang saya gunakan yang belum saya lihat yang dirujuk dalam jawaban lain
https://github.com/brminnick/AsyncAwaitBestPractices
Jika Anda perlu "Fire And Forget", Anda memanggil metode ekstensi pada tugas.
Melewati tindakan pada Eksepsi ke panggilan memastikan bahwa Anda mendapatkan yang terbaik dari kedua dunia - tidak perlu menunggu eksekusi dan memperlambat pengguna Anda, sambil mempertahankan kemampuan untuk menangani pengecualian dengan cara yang anggun.
Dalam contoh Anda, Anda akan menggunakannya seperti ini:
Ini juga memberikan AsyncCommands yang dapat dilaksanakan dengan mengimplementasikan ICommand di luar kotak yang bagus untuk solusi MVVM Xamarin saya
sumber
Solusinya adalah mulai HttpClient ke dalam tugas eksekusi lain tanpa konteks penyatuan:
sumber
Jika Anda benar-benar ingin melakukan ini. Hanya untuk mengatasi "Panggil metode async dalam C # tanpa menunggu", Anda dapat menjalankan metode async di dalam a
Task.Run
. Pendekatan ini akan menunggu sampaiMyAsyncMethod
selesai.await
secara asinkron membuka bungkusResult
tugas Anda, sedangkan hanya menggunakan Hasil akan memblokir sampai tugas selesai.sumber
Metode async biasanya mengembalikan kelas Tugas. Jika Anda menggunakan
Wait()
metode atauResult
properti dan pelemparan kode pengecualian - tipe pengecualian dimasukkan ke dalamnyaAggregateException
- maka Anda perlu kueriException.InnerException
untuk menemukan pengecualian yang benar.Tapi itu juga mungkin untuk digunakan
.GetAwaiter().GetResult()
sebagai gantinya - itu juga akan menunggu tugas async, tetapi tidak akan membungkus pengecualian.Jadi, inilah contoh singkatnya:
Anda mungkin ingin juga dapat mengembalikan beberapa parameter dari fungsi async - yang dapat dicapai dengan memberikan tambahan
Action<return type>
ke fungsi async, misalnya seperti ini:Harap perhatikan bahwa metode async biasanya memiliki
ASync
penamaan suffix, hanya untuk dapat menghindari tabrakan antara fungsi sinkronisasi dengan nama yang sama. (MisalnyaFileStream.ReadAsync
) - Saya telah memperbarui nama fungsi untuk mengikuti rekomendasi ini.sumber