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
, dan case
pada setiap titik suspensi. Pada setiap titik penangguhan, fungsi menyimpan nilai case
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:
- Anda tidak dapat menyimpan status dalam variabel lokal di antara pengulangan.
- Anda tidak dapat menangguhkan "protothread" dari kedalaman panggilan yang sewenang-wenang. (semua titik suspensi harus pada level 0)
Ada beberapa solusi untuk keduanya:
- Semua variabel lokal harus ditarik ke konteks protothread (konteks yang sudah dibutuhkan oleh fakta bahwa protothread harus menyimpan titik kembalinya berikutnya)
- Jika Anda merasa Anda benar-benar perlu memanggil protothread lain dari protothread, "bibit" protothread anak dan tunda sampai selesai anak.
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
dan await
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.
public Task<object> AmIACoroutine() {
var tcs = new TaskCompletionSource<object>();
return tcs.Task;
}
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.