Jawaban:
Praktik terbaik adalah menandai fungsi async void
hanya jika itu api dan lupakan metode, jika Anda ingin menunggu, Anda harus menandainya sebagai async Task
.
Jika Anda masih ingin menunggu, maka bungkuslah seperti itu await Task.Run(() => blah())
await Task.Run(() => An_async_void_method_I_can_not_modify_now())
await Task.Run(() => blah())
menyesatkan. Ini tidak menunggu selesainya fungsi async blah
, itu hanya menunggu penciptaan (sepele) tugas, dan berlanjut segera sebelum blah()
selesai.
Thread.Sleep
tidak async. Pertanyaan ini adalah tentang menunggu suatu async void
fungsi, katakanlahasync void blah() { Task.Delay(10000); }
Solusi terbaik adalah menggunakan async Task
. Anda harus menghindari async void
karena beberapa alasan, salah satunya adalah kompabilitas.
Jika metode tidak dapat dibuat untuk kembali Task
(misalnya, itu adalah pengendali acara), maka Anda dapat menggunakan SemaphoreSlim
untuk memiliki sinyal metode ketika akan keluar. Pertimbangkan untuk melakukan ini di finally
blok.
lakukan AutoResetEvent, panggil fungsi lalu tunggu AutoResetEvent dan kemudian atur di dalam async void ketika Anda tahu itu selesai.
Anda juga bisa menunggu pada Tugas yang kembali dari kekosongan async Anda
Anda tidak perlu melakukan apa pun secara manual, await
kata kunci menjeda eksekusi fungsi sampai blah()
kembali.
private async void SomeFunction()
{
var x = await LoadBlahBlah(); <- Function is not paused
//rest of the code get's executed even if LoadBlahBlah() is still executing
}
private async Task<T> LoadBlahBlah()
{
await DoStuff(); <- function is paused
await DoMoreStuff();
}
T
adalah jenis blah()
pengembalian objek
Anda tidak bisa benar await
- benar void
fungsi jadi LoadBlahBlah()
tidak bisavoid
LoadBlahBlah()
sampai selesai, bukanblah()
Saya tahu ini adalah pertanyaan lama, tetapi ini masih merupakan masalah yang terus saya hadapi, namun masih belum ada solusi yang jelas untuk melakukan ini dengan benar ketika menggunakan async / menunggu dalam metode tanda tangan async void.
Namun, saya perhatikan bahwa. Tunggu () berfungsi dengan baik di dalam metode void.
dan karena async void dan void memiliki tanda tangan yang sama, Anda mungkin perlu melakukan hal berikut.
void LoadBlahBlah()
{
blah().Wait(); //this blocks
}
Async / wait yang cukup membingungkan tidak menghalangi pada kode selanjutnya.
async void LoadBlahBlah()
{
await blah(); //this does not block
}
Ketika Anda mendekompilasi kode Anda, tebakan saya adalah bahwa async void membuat Tugas internal (seperti Tugas async), tetapi karena tanda tangan tidak mendukung untuk mengembalikan tugas internal tersebut
ini berarti bahwa secara internal metode void async masih akan dapat "menunggu" metode async internal. tetapi secara eksternal tidak dapat mengetahui kapan tugas internal selesai.
Jadi kesimpulan saya adalah bahwa async void berfungsi sebagaimana mestinya, dan jika Anda memerlukan umpan balik dari Tugas internal, maka Anda harus menggunakan tanda tangan Tugas async sebagai gantinya.
semoga obrolan saya masuk akal bagi siapa pun yang juga mencari jawaban.
Sunting: Saya membuat beberapa contoh kode dan mendekompilasi untuk melihat apa yang sebenarnya terjadi.
static async void Test()
{
await Task.Delay(5000);
}
static async Task TestAsync()
{
await Task.Delay(5000);
}
Berubah menjadi (sunting: Saya tahu bahwa kode bodi tidak ada di sini tetapi di statemachine, tetapi statemachine pada dasarnya identik, jadi saya tidak repot menambahkannya)
private static void Test()
{
<Test>d__1 stateMachine = new <Test>d__1();
stateMachine.<>t__builder = AsyncVoidMethodBuilder.Create();
stateMachine.<>1__state = -1;
AsyncVoidMethodBuilder <>t__builder = stateMachine.<>t__builder;
<>t__builder.Start(ref stateMachine);
}
private static Task TestAsync()
{
<TestAsync>d__2 stateMachine = new <TestAsync>d__2();
stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
stateMachine.<>1__state = -1;
AsyncTaskMethodBuilder <>t__builder = stateMachine.<>t__builder;
<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
AsyncVoidMethodBuilder atau AsyncTaskMethodBuilder tidak benar-benar memiliki kode apa pun dalam metode Mulai yang akan mengisyaratkan mereka untuk memblokir, dan akan selalu berjalan secara tidak sinkron setelah dijalankan.
artinya tanpa Tugas kembali, tidak akan ada cara untuk memeriksa apakah sudah selesai.
seperti yang diharapkan, ia hanya memulai Task yang menjalankan async, dan kemudian melanjutkan dalam kode. dan Tugas async, pertama memulai Tugas, dan kemudian mengembalikannya.
jadi saya kira jawaban saya adalah untuk tidak pernah menggunakan async void, jika Anda perlu tahu kapan tugas itu selesai, itulah tugas Async.