Anda mengajukan beberapa pertanyaan dalam pertanyaan Anda. Saya akan memecahnya sedikit berbeda dari yang Anda lakukan. Tapi pertama izinkan saya langsung menjawab pertanyaan.
Kita semua menginginkan kamera yang ringan, berkualitas tinggi, dan murah, tetapi seperti kata pepatah, Anda hanya bisa mendapatkan paling banyak dua dari tiga. Anda berada dalam situasi yang sama di sini. Anda menginginkan solusi yang efisien, aman, dan berbagi kode antara jalur sinkron dan asinkron. Anda hanya akan mendapatkan dua dari itu.
Biarkan saya menjelaskan mengapa itu. Kami akan mulai dengan pertanyaan ini:
Saya melihat bahwa orang mengatakan Anda dapat menggunakan GetAwaiter().GetResult()
metode async dan memintanya dari metode sinkronisasi Anda? Apakah utas itu aman di semua skenario?
Inti dari pertanyaan ini adalah "dapatkah saya membagikan jalur sinkron dan asinkron dengan membuat jalur sinkron hanya menunggu secara sinkron pada versi asinkron?"
Biarkan saya menjadi sangat jelas tentang hal ini karena ini penting:
ANDA HARUS SEGERA BERHENTI MENGAMBIL NASIHAT DARI MEREKA ORANG .
Itu saran yang sangat buruk. Sangat berbahaya untuk secara sinkron mengambil hasil dari tugas asinkron kecuali Anda memiliki bukti bahwa tugas telah selesai secara normal atau tidak normal .
Alasan mengapa ini saran yang sangat buruk adalah, yah, pertimbangkan skenario ini. Anda ingin memotong rumput, tetapi bilah pemotong rumput Anda rusak. Anda memutuskan untuk mengikuti alur kerja ini:
- Pesan bilah baru dari situs web. Ini adalah operasi latensi tinggi, asinkron.
- Sinkron menunggu - yaitu, tidur sampai Anda memiliki pisau di tangan .
- Periksa kotak surat secara berkala untuk melihat apakah blade telah tiba.
- Hapus bilah dari kotak. Sekarang Anda memilikinya di tangan.
- Pasang pisau di mesin pemotong rumput.
- Memotong rumput.
Apa yang terjadi? Anda tidur selamanya karena operasi memeriksa surat sekarang terjaga keamanannya pada sesuatu yang terjadi setelah surat tiba .
Sangat mudah untuk masuk ke situasi ini ketika Anda secara serentak menunggu tugas yang sewenang-wenang. Tugas itu mungkin sudah dijadwalkan di masa depan utas yang sekarang menunggu , dan sekarang masa depan itu tidak akan pernah tiba karena Anda sedang menunggu untuk itu.
Jika Anda melakukan menunggu asinkron maka semuanya baik-baik saja! Anda memeriksa surat secara berkala, dan saat Anda menunggu, Anda membuat sandwich atau melakukan pajak atau apa pun; Anda terus menyelesaikan pekerjaan sambil menunggu.
Jangan menunggu secara sinkron. Jika tugas selesai, itu tidak perlu . Jika tugas tidak dilakukan tetapi dijadwalkan untuk menjalankan utas saat ini, itu tidak efisien karena utas saat ini dapat melayani pekerjaan lain alih-alih menunggu. Jika tugas tidak selesai dan jadwal berjalan pada utas saat ini, itu tergantung menunggu secara sinkron. Tidak ada alasan yang baik untuk menunggu secara sinkron, lagi, kecuali jika Anda sudah tahu bahwa tugas sudah selesai .
Untuk membaca lebih lanjut tentang topik ini, lihat
https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
Stephen menjelaskan skenario dunia nyata jauh lebih baik daripada yang saya bisa.
Sekarang mari kita pertimbangkan "arah lain". Bisakah kita membagikan kode dengan membuat versi asinkron hanya melakukan versi sinkron pada utas pekerja?
Itu mungkin dan memang mungkin ide yang buruk, karena alasan berikut.
Itu tidak efisien jika operasi sinkron adalah pekerjaan IO latensi tinggi. Ini pada dasarnya mempekerjakan seorang pekerja dan membuat pekerja itu tidur sampai tugas selesai. Utas sangat mahal . Mereka mengkonsumsi sejuta byte address space minimum secara default, mereka butuh waktu, mereka mengambil sumber daya sistem operasi; Anda tidak ingin membakar utas melakukan pekerjaan yang tidak berguna.
Operasi sinkron mungkin tidak ditulis agar aman utas.
Ini adalah teknik yang lebih masuk akal jika pekerjaan dengan latensi tinggi terikat prosesor, tetapi jika demikian maka Anda mungkin tidak ingin menyerahkannya kepada pekerja. Anda mungkin ingin menggunakan pustaka tugas paralel untuk memparalelkannya ke CPU sebanyak mungkin, Anda mungkin ingin logika pembatalan, dan Anda tidak bisa begitu saja membuat versi sinkron melakukan semua itu, karena dengan demikian itu akan menjadi versi asinkron .
Bacaan lebih lanjut; sekali lagi, Stephen menjelaskannya dengan sangat jelas:
Mengapa tidak menggunakan Task.Run:
https://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-using.html
Lebih banyak skenario "lakukan dan jangan" untuk Task.Run:
https://blog.stephencleary.com/2013/11/taskrun-etiquette-examples-dont-use.html
Lalu, apa yang tersisa dari kita? Kedua teknik untuk berbagi kode menyebabkan deadlock atau inefisiensi besar. Kesimpulan yang kami capai adalah bahwa Anda harus membuat pilihan. Apakah Anda ingin program yang efisien dan benar serta menyenangkan penelepon, atau Anda ingin menyimpan beberapa penekanan tombol yang diperlukan dengan menduplikasi sejumlah kecil kode antara jalur sinkron dan asinkron? Anda tidak mendapatkan keduanya, saya khawatir.