Saya baru saja mulai bermain-main dengan async / menunggu di .Net 4.5. Satu hal yang saya awalnya ingin tahu, mengapa kata kunci async diperlukan? Penjelasan yang saya baca adalah bahwa itu adalah penanda sehingga kompiler tahu metode menunggu sesuatu. Tapi sepertinya kompiler harus bisa mengetahui ini tanpa kata kunci. Jadi apa lagi fungsinya?
19
Jawaban:
Ada beberapa jawaban di sini, dan semuanya berbicara tentang apa yang dilakukan metode async, tetapi tidak satupun dari mereka menjawab pertanyaan, itulah mengapa
async
diperlukan sebagai kata kunci yang masuk dalam deklarasi fungsi.Ini bukan "untuk mengarahkan kompiler untuk mengubah fungsi dengan cara khusus";
await
sendirian bisa melakukan itu. Mengapa? Karena C # sudah memiliki mekanisme lain di mana kehadiran kata kunci khusus dalam tubuh metode menyebabkan compiler untuk melakukan ekstrim (dan sangat mirip denganasync/await
) transformasi pada tubuh metode:yield
.Kecuali itu
yield
bukan kata kunci sendiri dalam C #, dan memahami mengapa akan menjelaskanasync
juga. Tidak seperti di sebagian besar bahasa yang mendukung mekanisme ini, di C # Anda tidak bisa mengatakanyield value;
Anda harus mengatakannyayield return value;
. Mengapa? Karena itu ditambahkan ke bahasa setelah C # sudah ada, dan itu cukup masuk akal untuk mengasumsikan bahwa seseorang, di suatu tempat, mungkin telah digunakanyield
sebagai nama variabel. Tetapi karena tidak ada skenario yang sudah ada sebelumnya yang<variable name> return
secara sintaksis benar,yield return
ditambahkan ke bahasa untuk memungkinkan untuk memperkenalkan generator sambil mempertahankan kompatibilitas mundur 100% dengan kode yang ada.Dan inilah mengapa
async
ditambahkan sebagai pengubah fungsi: untuk menghindari kerusakan kode yang ada yang digunakanawait
sebagai nama variabel. Karena tidak adaasync
metode yang sudah ada, tidak ada kode lama yang tidak valid, dan dalam kode baru, kompiler dapat menggunakan keberadaanasync
tag untuk mengetahui yangawait
harus diperlakukan sebagai kata kunci dan bukan pengidentifikasi.sumber
async
kata kunci dapat dibatalkan? Jelas itu akan menjadi terobosan BC tetapi dapat dianggap mempengaruhi sangat sedikit proyek dan menjadi persyaratan langsung untuk meningkatkan (yaitu mengubah nama variabel).itu mengubah metode dari metode normal ke objek dengan panggilan balik yang memerlukan pendekatan yang sama sekali berbeda untuk pembuatan kode
dan ketika sesuatu yang drastis seperti itu terjadi adalah kebiasaan untuk menandakannya dengan jelas (kami belajar pelajaran itu dari C ++)
sumber
async
s pada saat yang sama sehingga mereka tidak menjalankan satu demi satu tetapi secara bersamaan (jika utas tersedia setidaknya)Task<T>
sebenarnya memiliki karakteristik sebuahasync
metode - misalnya, Anda mungkin hanya berjalan melalui beberapa logika bisnis / pabrik dan kemudian mendelegasikan beberapa lainnya metode kembaliTask<T>
.async
metode memiliki tipeTask<T>
pengembalian tanda tangan tetapi tidak benar - benar mengembalikanTask<T>
, mereka hanya mengembalikan aT
. Untuk mengetahui semua ini tanpaasync
kata kunci, kompiler C # harus melakukan segala macam pemeriksaan mendalam terhadap metode ini, yang mungkin akan memperlambatnya sedikit, dan menyebabkan segala macam ambiguitas.Seluruh gagasan dengan kata kunci seperti "async" atau "tidak aman" adalah untuk menghapus ambiguitas tentang bagaimana kode yang mereka modifikasi harus diperlakukan. Dalam kasus kata kunci async, ia memberitahu kompiler untuk memperlakukan metode yang dimodifikasi sebagai sesuatu yang tidak perlu kembali segera. Ini memungkinkan utas tempat metode ini digunakan untuk melanjutkan tanpa harus menunggu hasil dari metode itu. Ini secara efektif optimasi kode.
sumber
OK, ini saya ambil.
Ada sesuatu yang disebut coroutine yang telah dikenal selama beberapa dekade. ("Knuth and Hopper" -class "selama beberapa dekade") Mereka adalah generalisasi dari subrutin , sedemikian rupa sehingga mereka tidak hanya mendapatkan dan melepaskan kontrol pada pernyataan fungsi mulai dan kembali, tetapi mereka juga melakukannya pada titik tertentu ( titik suspensi ). Subrutin adalah coroutine tanpa titik suspensi.
Mereka adalah PLAIN MUDAH untuk menerapkan dengan makro C, seperti yang ditunjukkan dalam makalah berikut tentang "protothreads". ( http://dunkels.com/adam/dunkels06protothreads.pdf ) Baca. Aku akan menunggu...
Intinya adalah bahwa makro membuat label besar
switch
, dancase
pada setiap titik suspensi. Pada setiap titik penangguhan, fungsi menyimpan nilaicase
label segera berikut , sehingga ia tahu di mana untuk melanjutkan eksekusi pada saat dipanggil. Dan itu mengembalikan kontrol ke penelepon.Ini dilakukan tanpa mengubah aliran kontrol kode yang dijelaskan dalam "protothread".
Bayangkan sekarang bahwa Anda memiliki lingkaran besar yang memanggil semua "protothreads" ini pada gilirannya, dan Anda secara bersamaan menjalankan "protothreads" pada satu utas.
Pendekatan ini memiliki dua kelemahan:
Ada beberapa solusi untuk keduanya:
Dan jika Anda memiliki dukungan kompiler untuk melakukan pekerjaan menulis ulang yang dilakukan oleh makro dan solusi, well, Anda bisa menulis kode protothread Anda seperti yang Anda inginkan dan memasukkan titik-titik suspensi dengan kata kunci.
Dan ini adalah apa
async
danawait
semua tentang: membuat coroutine (stackless).Coroutine di C # diverifikasi sebagai objek dari kelas (generik atau non-generik)
Task
.Saya menemukan kata kunci ini sangat menyesatkan. Bacaan mental saya adalah:
async
sebagai "suspensible"await
sebagai "tunda sampai selesai"Task
sebagai "masa depan ..."Sekarang. Apakah kita benar-benar perlu menandai fungsinya
async
? Selain mengatakan bahwa itu harus memicu mekanisme penulisan ulang kode untuk membuat fungsi menjadi coroutine, itu menyelesaikan beberapa ambiguitas. Pertimbangkan kode ini.Dengan asumsi itu
async
tidak wajib, apakah ini coroutine atau fungsi normal? Haruskah kompiler menulis ulang sebagai coroutine atau tidak? Keduanya bisa dimungkinkan dengan semantik akhirnya yang berbeda.sumber