Sekarang kita tahu apa yang tersedia untuk c # 5, tampaknya masih ada celah bagi kita untuk memengaruhi pilihan dua kata kunci baru untuk ' Asynchrony ' yang diumumkan oleh Anders Heijsberg kemarin di PDC10 .
async void ArchiveDocuments(List<Url> urls) {
Task archive = null;
for(int i = 0; i < urls.Count; ++i) {
var document = await FetchAsync(urls[i]);
if (archive != null)
await archive;
archive = ArchiveAsync(document);
}
}
Eric Lippert memiliki penjelasan tentang pilihan dua kata kunci saat ini, dan cara mereka salah mengerti dalam studi kegunaan. Komentar memiliki beberapa proposisi lain.
Tolong - satu saran per jawaban, duplikat akan dihapus.
Jawaban:
Mengingat bahwa saya tidak jelas tentang arti / keperluan
async
, saya tidak bisa benar-benar membantahnya, tetapi saran terbaik saya untuk menggantiawait
adalah:yield while
(lihat! tidak ada kata kunci baru)Catatan setelah memikirkan hal ini sedikit lebih banyak, saya bertanya-tanya apakah menggunakan kembali
while
cara ini adalah ide yang baik - kecenderungan alami akan mengharapkan boolean sesudahnya.(Berpikir: menemukan kata kunci yang baik seperti mencari nama domain yang bagus :)
sumber
while(x) {...}
, jikax
salah.while
. Jika Anda menambahkan kata kerja, sepertido
, maka Anda dapatdo {...} while (x)
, yang mengeksekusi tubuh terlepas dari x (setidaknya sekali). Saran Andayield while
tampaknya sangat miripdo while
, tetapi dengan jaminan yang berlawanan untuk melakukan kata kerja, yang mungkin agak menyesatkan (tapi tidak terlalu banyak masalah besar). Hal yang paling tidak saya sukaiyield
adalah bahwa itu menyiratkan implementasi suatu mekanisme. Inti dariasync
/await
adalah bahwa Anda menulis operasi asinkron dengan gaya sinkron.yield
memecah gaya sinkron itu.await
kata kunci akan dikenali berdasarkan konteks, jadi Anda masih bisa memiliki metode atau variabel bernama "menunggu" jika Anda mau. Untuk beberapa derajat, saya pikir menggunakan kata kunci baru untuk fungsi baru kurang membingungkan daripada menggunakan kembali kata kunci yang ada berarti lebih dari satu hal. (contoh berlebihan: dangermouse.net/esoteric/ook.html )Bagaimana kalau tidak memiliki kata kunci?
Saya ingin kompiler menyadari bahwa, sebagian besar waktu, ketika saya memanggil metode asinkron, saya ingin hasilnya.
Itu dia. Alasan orang mengalami kesulitan memikirkan kata kunci untuk hal ini adalah karena itu seperti memiliki kata kunci untuk "lakukan hal yang akan Anda lakukan jika semuanya normal". Itu harus menjadi default, tidak memerlukan kata kunci.
Memperbarui
Saya awalnya menyarankan kompiler harus pintar dengan inferensi tipe untuk mencari tahu apa yang harus dilakukan. Berpikir lebih jauh tentang ini, saya akan menjaga implementasi yang ada di CTP seperti apa adanya, tetapi membuat beberapa tambahan sepele untuk itu, sehingga untuk mengurangi kasus di mana Anda harus menggunakan
await
kata kunci secara eksplisit.Kami menciptakan sebuah atribut:
[AutoAwait]
. Ini hanya dapat diterapkan pada metode. Salah satu cara untuk menerapkan ini pada metode Anda adalah menandainyaasync
. Tetapi Anda juga bisa melakukannya dengan tangan, misalnya:Kemudian di dalam
async
metode apa pun , kompiler akan menganggap Anda ingin menunggu panggilanDownloadDocumentAsync
, jadi Anda tidak perlu menentukannya. Panggilan apa pun ke metode itu akan secara otomatis menunggunya.Sekarang, jika Anda ingin "menjadi pintar" dan memperoleh
Task<Document>
, Anda menggunakan operatorstart
, yang hanya dapat muncul sebelum pemanggilan metode:Rapi, saya pikir. Sekarang pemanggilan metode biasa berarti apa yang biasanya artinya: tunggu sampai metode selesai. Dan
start
menunjukkan sesuatu yang berbeda: jangan menunggu.Untuk kode yang muncul di luar
async
metode, satu-satunya cara Anda diizinkan memanggil[AutoAwait]
metode adalah dengan mengawali dengan metode tersebutstart
. Ini memaksa Anda untuk menulis kode yang memiliki arti yang sama terlepas dari apakah kode itu muncul dalamasync
metode atau tidak.Lalu saya mulai menjadi serakah! :)
Pertama, saya ingin
async
menerapkan metode antarmuka:Ini pada dasarnya berarti bahwa metode implementasi harus kembali
Task<int>
atau sesuatu yang kompatibel denganawait
, dan penelepon ke metode tersebut akan mendapatkan[AutoAwait]
perilaku.Juga ketika saya menerapkan metode di atas, saya ingin dapat menulis:
Jadi saya tidak perlu menyebutkan
Task<int>
sebagai tipe pengembalian.Juga, saya ingin
async
menerapkan tipe delegasi (yang, bagaimanapun juga, seperti antarmuka dengan satu metode). Begitu:Seorang
async
delegasi memiliki - Anda dapat menebaknya -[AutoAwait]
perilaku. Dari suatuasync
metode Anda dapat memanggilnya dan itu akan secara otomatisawait
diedit (kecuali jika Anda memilih untuk melakukannya sajastart
). Jadi jika Anda mengatakan:Itu hanya berfungsi. Ini bukan panggilan metode. Belum ada tugas yang dimulai - dan
async delegate
bukan tugas. Ini pabrik untuk membuat tugas. Anda bisa mengatakan:Dan itu akan memulai tugas dan menunggu sampai selesai dan memberi Anda hasilnya. Atau Anda bisa mengatakan:
Jadi satu tempat di mana "pipa ledeng" bocor adalah bahwa jika Anda ingin membuat delegasi ke suatu
async
metode, Anda harus tahu untuk menggunakan suatuasync delegate
tipe. Jadi, bukannyaFunc
Anda harus mengatakanAsyncFunc
, dan seterusnya. Meskipun suatu hari hal semacam itu mungkin diperbaiki oleh inferensi tipe yang ditingkatkan.Pertanyaan lain adalah apa yang harus terjadi jika Anda mengatakan mulai dengan metode biasa (non-async). Jelas kesalahan kompilasi akan menjadi opsi yang aman. Tetapi ada kemungkinan lain.
sumber
var
, berpotensi harus mengganti beberapa jenis nama eksplisit panjang, dan juga ambigu antaraawait
kasus dan kasus di mana seseorang secara tidak sengaja menyebut metode async bukan metode sinkron normal. Tampaknya intuitif pada awalnya tetapi sebenarnya melanggar prinsip paling tidak mengejutkan.var
? Saya ingin tahu apakah Anda merespons revisi sebelumnya atas jawaban saya ... Saya sudah menulis ulang sepenuhnya. Anda sekarang dapat memikirkan saran ini sebagai berikut: jika metode ini ditandai dengan atribut khusus, seolah-olahawait
kata kunci tersebut secara otomatis dimasukkan di depan panggilan ke metode itu (kecuali jika Anda menekan ini denganstart
awalan). Semuanya tetap persis seperti dalam CTP, dan karenanyavar
berfungsi dengan baik.public async Task<int> FooAsync()
.(jika Anda tidak mengerti, baca entri blog Eric . Setidaknya lebih baik daripada
for sooth Romeo wherefore art thou AsyncFetch(…)
)sumber
Saya pikir
async
baik-baik saja, tapi mungkin itu karena saya mengasosiasikannya dengan halaman ASP.NET async - ide yang sama.Untuk
await
kata kunci yang saya sukacontinue after
atauresume after
.Saya tidak suka
yield
atau salah satu variannya, karena semantiknya sedemikian rupa sehingga metodenya mungkin tidak pernah benar-benar menghasilkan eksekusi; itu tergantung pada keadaan tugas.sumber
resume after
untukawait
. Mungkinasync
bisa dipanggilresumable
.after
,continue after
pendekatan ini memiliki keunggulan implementasi yang kuat: itu termasuk kata kunci kontekstual yang ada saat ini, tetapi dengan sintaksis yang tidak kompatibel dengan penggunaan saat ini. Itu menjamin bahwa penambahan tidak akan merusak kode yang ada. Saat menggunakan kata kunci yang sama sekali baru, implementasi perlu mengatasi kemungkinan penggunaan kata sebagai pengidentifikasi pada kode lama, yang bisa menjadi sangat rumit.Saya menambahkan komentar di blog Eric juga, saya tidak melihat masalah dengan menggunakan kata kunci yang sama
async
Saya hanya menyatakan bahwa saya ingin mengunduh file secara tidak sinkron. Ada sedikit redundensi di sini, "async" muncul dua kali, karena itu ada dalam nama metode juga. Compiler dapat menjadi lebih pintar dan mendeteksi konvensi bahwa metode yang diakhiri dengan "Async" adalah metode async yang benar, dan menambahkannya bagi kita dalam kode yang dikompilasi. Jadi, alih-alih Anda mungkin hanya ingin menelepon
sebagai lawan memanggil yang sinkron
Heck, kita juga harus dapat mendefinisikannya dengan cara yang sama, karena kata kunci async ada dalam deklarasi kita, mengapa kita harus menambahkan "Async" secara manual ke setiap nama metode - kompilator dapat melakukannya untuk kita.
sumber
async
kata kunci pada metode ini hanyalah keramahtamahan (jika saya mengerti dengan benar), saya bertanya-tanya apakah hal terbaik tidak akan melakukan kebalikan dari apa yang Anda sarankan: tinggalkanasync
metode tersebut, dan gunakan saja di mana mereka saat iniawait
.async Task<Byte[]> DownloadFile(...)
alih-alihTask<Byte[]> DownloadFileAsync(...)
(Yang terakhir akan menjadi tanda tangan yang dikompilasi). Either way bekerja.async = tugas - Memodifikasi fungsi untuk mengembalikan tugas, jadi mengapa tidak menggunakan kata kunci "tugas"?
await = finish - Kami tidak perlu menunggu, tetapi tugas harus "selesai" sebelum menggunakan hasilnya.
sumber
Saya suka
yield until
.yield while
, sudah disarankan, bagus dan tidak memperkenalkan kata kunci baru, tapi saya pikir "sampai" menangkap perilaku sedikit lebih baik.Saya pikir
yield <something>
ini adalah ide yang hebat, karena hasil sudah menangkap ide membuat sisa metode ini menjadi kelanjutan yang sangat baik. Mungkin seseorang bisa memikirkan kata yang lebih baik daripada "sampai."sumber
Saya hanya ingin mendaftarkan suara saya untuk saran Aaron G tentang
comefrom
- penggunaan yang tepat pertama yang saya lihat dari pernyataan COMEFROM INTERCAL . Idenya adalah bahwa itu kebalikan dari GOTO (melompat dari pernyataan GOTO) karena membuat beberapa tempat dalam kode Anda melompat ke pernyataan COMEFROM.sumber
Karena kita berurusan dengan
Task<T>
s, bagaimana menggunakanstart
kata kunci sebelum pernyataan, seperti pada:start var document = FetchAsync(urls[i]);
sumber
finish
lebih baik dari itustart
?Perlu dicatat bahwa F # juga menggunakan
async
kata kunci dalam alur kerja async-nya, yang hampir sama persis dengan fungsi async baru di C # 5. Karena itu, saya akan menjaga yang samaUntuk
await
kata kunci dalam F #, mereka hanya menggunakanlet!
bukanlet
. C # tidak memiliki sintaks tugas yang sama, sehingga mereka membutuhkan sesuatu di sisi kanan=
tanda. Seperti yang dikatakan Benjol, fungsinya samayield
sehingga hampir menjadi varian dari itu.sumber
do!
, tetapi Anda tahu bahwa ...yield async FetchAsync(..)
Ini berjalan sempurna dengan
async
pengubah yang Anda butuhkan pada metode yang Anda minta. Dan juga semantik dari saatyield return
ini, Anda kembali dan menghasilkan eksekusi ke kode penghitungan sementara dalam hal ini Anda menghasilkan eksekusi Anda ke metode asinkron.Bayangkan jika di masa depan akan ada kegunaan lain untuk
yield
, kita bisa menambahkan diyield x
mana x adalah fitur baru yang mengkilap alih-alih memiliki semua kata kunci yang berbeda untuk melakukan sebagian besar hal yang sama, menghasilkan eksekusi.Terus terang, saya tidak begitu mengerti argumen 'tidak menghasilkan eksekusi'. Lagi pula, bukankah titik memanggil metode lain sudah untuk 'menghasilkan eksekusi' ke metode itu? Terlepas dari apakah itu asinkron atau tidak? Saya saya kehilangan sesuatu di sini?
Dan bagus untuk Anda jika
async
pengembaliannya sinkron tetapi memiliki kata kunci di sana harus menandakan bahwa ada kemungkinan metode tersebut akan berjalan secara tidak sinkron dan Anda akan menghasilkan eksekusi ke metode lain. Metode Anda harus menjelaskan hal itu terlepas dari apakah metode itu benar-benar melakukan panggilan tidak sinkron atau tidak.IMO Saya pikir berbagai kasus 'tidak menghasilkan' adalah detail implementasi. Saya lebih suka menjamin konsistensi dalam bahasa (yaitu menggunakan kembali
yield
).sumber
Bagaimana
complete
, seperti dalam "Saya ingin tugas selesai"?sumber
task
(untuk deklarasi metode) danasync
(dalam tubuh metode)sumber