Jawaban Slaks dan Killercam baik; Saya pikir saya akan menambahkan sedikit lebih banyak konteks.
Pertanyaan pertama Anda pada dasarnya adalah tentang metode apa yang dapat ditandai async
.
Metode yang ditandai sebagai async
dapat kembali void
, Task
atau Task<T>
. Apa perbedaan di antara mereka?
Sebuah Task<T>
metode async kembali dapat ditunggu, dan ketika tugas selesai akan mengajukan up T. sebuah
Sebuah Task
metode async kembali dapat ditunggu, dan ketika selesai tugas, kelanjutan dari tugas dijadwalkan untuk berjalan.
SEBUAH void
metode async kembali tidak dapat ditunggu; itu adalah metode "tembak dan lupakan". Itu bekerja secara tidak sinkron, dan Anda tidak memiliki cara untuk mengetahui kapan itu dilakukan. Ini lebih dari sedikit aneh; seperti kata SLaks, biasanya Anda hanya akan melakukan itu ketika membuat pengendali event asinkron. Acara menyala, pawang mengeksekusi; tidak ada yang akan "menunggu" tugas dikembalikan oleh pengendali acara karena penangan acara tidak mengembalikan tugas, dan bahkan jika mereka melakukannya, kode apa yang akan menggunakan Tugas untuk sesuatu? Biasanya bukan kode pengguna yang mentransfer kontrol ke handler sejak awal.
Pertanyaan kedua Anda, dalam komentar, pada dasarnya adalah tentang apa yang bisa await
diedit:
Metode apa yang bisa await
diedit? Apakah metode pengembalian yang dibatalkan dapat await
diedit?
Tidak, metode pengembalian batal tidak bisa ditunggu. Kompiler diterjemahkan await M()
menjadi panggilan ke M().GetAwaiter()
, di mana GetAwaiter
mungkin metode instance atau metode ekstensi. Nilai yang ditunggu harus berupa nilai yang bisa Anda dapatkan sebagai penunggu; jelas metode pengembalian-kembali tidak menghasilkan nilai dari mana Anda bisa mendapatkan penunggu.
Task
-Mengembalikan metode dapat menghasilkan nilai yang bisa ditunggu. Kami mengantisipasi bahwa pihak ketiga akan ingin membuat implementasi sendiri Task
objek-seperti yang dapat ditunggu, dan Anda akan dapat menunggu mereka. Namun, Anda tidak akan diizinkan untuk mendeklarasikan async
metode yang mengembalikan apa pun kecuali void
, Task
atau Task<T>
.
(PEMBARUAN: Kalimat terakhir saya mungkin dipalsukan oleh versi C # yang akan datang; ada proposal untuk memperbolehkan tipe yang dikembalikan selain tipe tugas untuk metode async.)
(PEMBARUAN: Fitur yang disebutkan di atas berhasil masuk ke C # 7.)
async void
metode meningkatkan pengecualian mereka padaSynchronizationContext
yang aktif pada saat mereka mulai mengeksekusi. Ini mirip dengan perilaku penangan acara (sinkron). @DrewMarsh: theUnobservedTaskException
dan runtime pengaturan hanya berlaku untuk "api dan lupa" async Task metode, tidakasync void
metode.Dalam hal penelepon ingin menunggu tugas atau menambah kelanjutan.
Faktanya, satu-satunya alasan untuk kembali
void
adalah jika Anda tidak dapat kembaliTask
karena Anda sedang menulis event handler.sumber
void
, Anda tidak memiliki cara untuk mendapatkan tugas yang dihasilkannya. (Sebenarnya, saya tidak yakin apakah itu menghasilkanTask
sama sekali)Metode yang kembali
Task
danTask<T>
dapat dikomposisikan - artinya Anda dapatawait
melakukannya di dalam suatuasync
metode.async
metode pengembalianvoid
tidak dapat dikomposisikan, tetapi mereka memiliki dua sifat penting lainnya:Poin kedua penting ketika Anda berurusan dengan konteks yang mempertahankan jumlah operasi asinkron yang luar biasa.
Konteks ASP.NET adalah salah satu konteks tersebut; jika Anda menggunakan
Task
metode async tanpa menunggu mereka darivoid
metode async , maka permintaan ASP.NET akan diselesaikan terlalu dini.Konteks lain adalah
AsyncContext
saya menulis untuk pengujian unit (tersedia di sini ) -AsyncContext.Run
metode melacak jumlah operasi yang beredar dan kembali ketika itu nol.sumber
Jenis
Task<T>
adalah jenis pekerja keras dari Perpustakaan Tugas Paralel (TPL), itu mewakili konsep "beberapa pekerjaan / pekerjaan yang akan menghasilkan hasil ketikT
di masa depan". Konsep "pekerjaan yang akan selesai di masa depan tetapi tidak mengembalikan hasil" diwakili oleh jenis Tugas non-generik.Tepatnya bagaimana hasil tipe
T
akan diproduksi dan detail implementasi dari tugas tertentu; pekerjaan mungkin dialihkan ke proses lain pada mesin lokal, ke utas lainnya, dll. Tugas TPL biasanya dialihkan ke utas pekerja dari kumpulan utas dalam proses saat ini, tetapi detail implementasi tidak mendasar padaTask<T>
jenisnya; melainkanTask<T>
dapat mewakili operasi latensi tinggi yang menghasilkan aT
.Berdasarkan komentar Anda di atas:
The
await
berarti ekspresi "mengevaluasi ungkapan ini untuk mendapatkan sebuah benda yang mewakili pekerjaan yang akan di masa depan menghasilkan hasil. Mendaftar sisa dari metode saat ini sebagai panggilan kembali terkait dengan kelanjutan tugas itu. Setelah tugas yang diproduksi dan kembali panggilan sudah terdaftar, segera kembalikan kontrol ke pemanggil saya ". Ini bertentangan / berbeda dengan pemanggilan metode biasa, yang berarti "ingat apa yang Anda lakukan, jalankan metode ini sampai benar-benar selesai dan kemudian mengambil di mana Anda tinggalkan, sekarang mengetahui hasil dari metode".Sunting: Saya harus mengutip artikel Eric Lippert pada Oktober 2011 MSDN Magazine karena ini sangat membantu saya dalam memahami hal ini sejak awal.
Untuk informasi lebih lanjut dan whitepage lihat di sini .
Saya harap ini bisa membantu.
sumber