Ekspresi asinkron
Artikel ini menjelaskan dukungan dalam F# untuk ekspresi asinkron. Ekspresi asinkron menyediakan satu cara untuk melakukan komputasi secara asinkron, yaitu tanpa menghalangi eksekusi pekerjaan lain. Misalnya, komputasi asinkron dapat digunakan untuk menulis aplikasi yang memiliki UI yang tetap responsif terhadap pengguna saat aplikasi melakukan pekerjaan lain. Model pemrograman Alur Kerja Asinkron F# memungkinkan Anda menulis program fungsional sambil menyembunyikan detail transisi alur dalam pustaka.
Kode asinkron juga dapat ditulis menggunakan ekspresi tugas, yang membuat tugas .NET secara langsung. Menggunakan ekspresi tugas lebih disukai saat beroperasi secara ekstensif dengan pustaka .NET yang membuat atau menggunakan tugas .NET. Saat menulis sebagian besar kode asinkron dalam F#, ekspresi asinkron F# lebih disukai karena lebih ringkas, lebih komposisional, dan menghindari peringatan tertentu terkait dengan tugas .NET.
Sintaks
async { expression }
Keterangan
Dalam sintaks sebelumnya, komputasi yang diwakili oleh expression
diatur untuk berjalan secara asinkron, yaitu, tanpa memblokir utas komputasi saat ini ketika operasi tidur asinkron, I/O, dan operasi asinkron lainnya dilakukan. Komputasi asinkron sering dimulai pada utas latar belakang sementara eksekusi berlanjut di utas saat ini. Jenis ekspresinya adalah Async<'T>
, di mana 'T
adalah jenis yang dikembalikan oleh ekspresi saat kata kunci return
digunakan.
Kelas Async
ini menyediakan metode yang mendukung beberapa skenario. Pendekatan umumnya adalah membuat objek Async
yang mewakili komputasi atau komputasi yang ingin Anda jalankan secara asinkron, lalu memulai komputasi ini dengan menggunakan salah satu fungsi pemicu. Pemicu yang Anda gunakan tergantung pada apakah Anda ingin menggunakan utas saat ini, utas latar belakang, atau objek tugas .NET. Misalnya, untuk memulai komputasi asinkron pada utas saat ini, Anda dapat menggunakan Async.StartImmediate
. Saat Anda memulai komputasi asinkron dari utas UI, Anda tidak memblokir perulangan peristiwa utama yang memproses tindakan pengguna seperti penekanan tombol dan aktivitas mouse, sehingga aplikasi Anda tetap responsif.
Pengikatan Asinkron dengan Menggunakan let!
Dalam ekspresi asinkron, beberapa ekspresi dan operasi sinkron, dan beberapa asinkron. Ketika Anda memanggil metode secara asinkron, alih-alih pengikatan let
biasa, Anda menggunakan let!
. Efek dari let!
adalah mengaktifkan eksekusi untuk melanjutkan komputasi atau utas lain saat komputasi sedang dilakukan. Setelah sisi kanan pengikatan let!
kembali, ekspresi asinkron lainnya melanjutkan eksekusi.
Kode berikut menunjukkan perbedaan antara let
dan let!
. Baris kode yang menggunakan let
hanya membuat komputasi asinkron sebagai objek yang dapat Anda jalankan nanti dengan menggunakan, misalnya, Async.StartImmediate
atau Async.RunSynchronously
. Baris kode yang menggunakan let!
memulai komputasi dan melakukan penantian asinkron: utas ditangguhkan hingga hasilnya tersedia, di mana eksekusi titik berlanjut.
// let just stores the result as an asynchronous operation.
let (result1 : Async<byte[]>) = stream.AsyncRead(bufferSize)
// let! completes the asynchronous operation and returns the data.
let! (result2 : byte[]) = stream.AsyncRead(bufferSize)
let!
hanya dapat digunakan untuk menunggu komputasi asinkron F# Async<T>
secara langsung. Anda dapat menunggu jenis operasi asinkron lainnya secara tidak langsung:
- Tugas .NET, Task<TResult> dan Task non-generik, dengan menggabungkan
Async.AwaitTask
- Tugas nilai .NET, ValueTask<TResult> dan ValueTask non-generik, dengan menggabungkan
.AsTask()
danAsync.AwaitTask
- Objek apa pun yang mengikuti pola "GetAwaiter" yang ditentukan dalam F# RFC FS-1097, dengan menggabungkan
task { return! expr } |> Async.AwaitTask
.
Alur Kontrol
Ekspresi asinkron dapat mencakup konstruksi alur kontrol, seperti for .. in .. do
, while .. do
, try .. with ..
, try .. finally ..
, if .. then .. else
, dan if .. then ..
. Ini mungkin pada gilirannya mencakup konstruksi asinkron lebih lanjut, dengan pengecualian penanganan with
dan finally
, yang dijalankan secara sinkron.
Ekspresi asinkron F# tidak mendukung try .. finally ..
asinkron. Anda dapat menggunakan ekspresi tugas untuk kasus ini.
pengikatan use
danuse!
Dalam ekspresi asinkron, pengikatan use
dapat mengikat ke nilai jenis IDisposable. Untuk yang terakhir, operasi pembersihan pembuangan dijalankan secara asinkron.
Selain let!
, Anda dapat menggunakan use!
untuk melakukan pengikatan asinkron. Perbedaan antara let!
dan use!
sama dengan perbedaan antara let
dan use
. Untuk use!
, objek dibuang pada penutupan cakupan saat ini. Perhatikan bahwa dalam rilis F# saat ini, use!
tidak mengizinkan nilai diinisialisasi ke null, meskipun use
demikian.
Primitif Asinkron
Metode yang melakukan tugas asinkron tunggal dan mengembalikan hasilnya disebut primitif asinkron, dan ini dirancang khusus untuk digunakan dengan let!
. Beberapa primitif asinkron didefinisikan dalam pustaka inti F#. Dua metode tersebut untuk aplikasi Web didefinisikan dalam modul FSharp.Control.WebExtensions
: WebRequest.AsyncGetResponse
dan WebClient.AsyncDownloadString
. Kedua primitif mengunduh data dari halaman Web, diberikan URL. AsyncGetResponse
menghasilkan objek System.Net.WebResponse
, dan AsyncDownloadString
menghasilkan string yang merepresentasikan HTML untuk halaman Web.
Beberapa primitif untuk operasi I/O asinkron disertakan dalam modul FSharp.Control.CommonExtensions
. Metode ekstensi kelas System.IO.Stream
ini adalah Stream.AsyncRead
dan Stream.AsyncWrite
.
Anda juga dapat menulis primitif asinkron Anda sendiri dengan mendefinisikan fungsi atau metode yang isinya adalah ekspresi asinkron.
Untuk menggunakan metode asinkron dalam .NET Framework yang dirancang untuk model asinkron lain dengan model pemrograman asinkron F#, Anda membuat fungsi yang mengembalikan objek Async
F#. Pustaka F# memiliki fungsi yang membuatnya mudah untuk dilakukan.
Salah satu contoh penggunaan ekspresi asinkron disertakan di sini; ada banyak metode kelas Asinkron dalam dokumentasi.
Contoh ini menunjukkan cara menggunakan ekspresi asinkron untuk menjalankan kode secara paralel.
Dalam contoh kode berikut, fungsi fetchAsync
mendapatkan teks HTML yang dikembalikan dari permintaan Web. Fungsi fetchAsync
ini berisi blok kode asinkron. Ketika pengikatan dilakukan pada hasil primitif asinkron, dalam hal ini AsyncDownloadString
, let!
digunakan alih-alih let
.
Anda menggunakan fungsi Async.RunSynchronously
untuk menjalankan operasi asinkron dan menunggu hasilnya. Sebagai contoh, Anda dapat menjalankan beberapa operasi asinkron secara paralel dengan menggunakan fungsi Async.Parallel
bersama dengan fungsi Async.RunSynchronously
. Fungsi Async.Parallel
ini mengambil daftar objek Async
, menyiapkan kode untuk setiap objek tugas Async
agar berjalan secara paralel, dan mengembalikan objek Async
yang mewakili komputasi paralel. Sama seperti untuk satu operasi, Anda memanggil Async.RunSynchronously
untuk memulai eksekusi.
Fungsi runAll
ini meluncurkan tiga ekspresi asinkron secara paralel dan menunggu hingga semuanya selesai.
open System.Net
open Microsoft.FSharp.Control.WebExtensions
let urlList = [ "Microsoft.com", "http://www.microsoft.com/"
"MSDN", "http://msdn.microsoft.com/"
"Bing", "http://www.bing.com"
]
let fetchAsync(name, url:string) =
async {
try
let uri = new System.Uri(url)
let webClient = new WebClient()
let! html = webClient.AsyncDownloadString(uri)
printfn "Read %d characters for %s" html.Length name
with
| ex -> printfn "%s" (ex.Message);
}
let runAll() =
urlList
|> Seq.map fetchAsync
|> Async.Parallel
|> Async.RunSynchronously
|> ignore
runAll()
Lihat juga
Saran dan Komentar
https://aka.ms/ContentUserFeedback.
Segera hadir: Sepanjang tahun 2024 kami akan menghentikan penggunaan GitHub Issues sebagai mekanisme umpan balik untuk konten dan menggantinya dengan sistem umpan balik baru. Untuk mengetahui informasi selengkapnya, lihat:Kirim dan lihat umpan balik untuk