19-bo‘lim
Asinxron dasturlash
Async va Await, Task va Task(Of T), ketma-ket va parallel bajarish, Task.WhenAll va nega .Result xavfli.
Ushbu bo‘lim mundarijasi
Ba'zi amallar uzoq davom etadi: fayl o'qish, tarmoqdan ma'lumot olish, ma'lumotlar bazasiga so'rov. Ular paytida dastur kutib turmasligi kerak.
Oddiy va asinxron #
Module Dastur
Async Function Tayyorlash(nom As String,
vaqt As Integer) As Task(Of String)
Await Task.Delay(vaqt)
Return $"{nom} tayyor"
End Function
Sub Main()
MainAsync().GetAwaiter().GetResult()
End Sub
Async Function MainAsync() As Task
Console.WriteLine("Boshlandi")
Dim natija As String = Await Tayyorlash("Choy", 50)
Console.WriteLine(natija)
Console.WriteLine("Tugadi")
End Function
End Module
Boshlandi
Choy tayyor
Tugadi
Uchta yangi so'z:
| So'z | Ma'nosi |
|---|---|
Async | Bu funksiya ichida Await ishlatiladi |
Await | Natijani kut, lekin bloklama |
Task | "Kelajakda tugaydigan ish" |
Bu - VB ni C# dan ajratib turadigan muhim tafsilot.
C# da async Task Main() yozish mumkin. Visual Basic da esa
mumkin emas - kompilyator quyidagi xatoni beradi:
error BC30737: No accessible 'Main' method with an appropriate
signature was found
VB da Main faqat to'rt shaklda bo'ladi: Sub Main(),
Sub Main(args As String()), Function Main() As Integer va
Function Main(args As String()) As Integer. Ularning hech biri
Async bo'lolmaydi.
Shuning uchun odatdagi yechim - ikki qismga bo'lish:
Sub Main()
MainAsync().GetAwaiter().GetResult()
End Sub
Async Function MainAsync() As Task
' bu yerda Await yozish mumkin
End Function
Bu darslikdagi hamma asinxron misol shu shaklda yozilgan.
Task va Task(Of T) #
Module Dastur
Async Function Hisobla(a As Integer, b As Integer) As Task(Of Integer)
Await Task.Delay(30)
Return a + b
End Function
Async Function Xabar(matn As String) As Task
Await Task.Delay(30)
Console.WriteLine($"Xabar: {matn}")
End Function
Sub Main()
MainAsync().GetAwaiter().GetResult()
End Sub
Async Function MainAsync() As Task
Dim yigindi As Integer = Await Hisobla(15, 27)
Console.WriteLine(yigindi)
Await Xabar("yuborildi")
End Function
End Module
42
Xabar: yuborildi
Task(Of T)- qiymat qaytaradi (Functionga o'xshash).Task- qaytarmaydi (Subga o'xshash).
Ketma-ket va parallel #
Mana asinxron kodning asosiy foydasi:
Imports System.Diagnostics
Module Dastur
Async Function Ish(nom As String) As Task(Of String)
Await Task.Delay(200)
Return nom
End Function
Sub Main()
MainAsync().GetAwaiter().GetResult()
End Sub
Async Function MainAsync() As Task
Dim soat As Stopwatch = Stopwatch.StartNew()
Dim a As String = Await Ish("A")
Dim b As String = Await Ish("B")
Dim c As String = Await Ish("C")
soat.Stop()
Dim ketmaKet As Long = soat.ElapsedMilliseconds
soat.Restart()
Dim vazifalar() As Task(Of String) = {Ish("A"), Ish("B"), Ish("C")}
Dim natijalar() As String = Await Task.WhenAll(vazifalar)
soat.Stop()
Dim parallel As Long = soat.ElapsedMilliseconds
Console.WriteLine($"Natijalar: {String.Join(", ", natijalar)}")
Console.WriteLine($"Ketma-ket 500 ms dan ko'pmi: {ketmaKet > 500}")
Console.WriteLine($"Parallel 400 ms dan kammi: {parallel < 400}")
Console.WriteLine($"Parallel tezroqmi: {parallel < ketmaKet}")
End Function
End Module
Natijalar: A, B, C
Ketma-ket 500 ms dan ko'pmi: True
Parallel 400 ms dan kammi: True
Parallel tezroqmi: True
Uchta ish, har biri 200 ms:
- Ketma-ket: har bir
Awaitoldingisini kutadi - jami ~600 ms. - Parallel: uchalasi birga boshlanadi - jami ~200 ms.
Chiqishda 612 ms kabi aniq son emas, True yozilgan.
Sababi: aniq vaqt kompyuterga, yuklamaga va operatsion tizimga bog'liq. Bugun 612, ertaga 587 bo'lishi mumkin.
Shuning uchun darslikda chegara solishtiriladi. O'z kodingizda ham vaqtga bog'liq tekshiruvlarni shunday yozing - aniq songa tenglashtirmang.
Task.WhenAll natijalari tartibi #
Module Dastur
Async Function Ish(nom As String, vaqt As Integer) As Task(Of String)
Await Task.Delay(vaqt)
Return nom
End Function
Sub Main()
MainAsync().GetAwaiter().GetResult()
End Sub
Async Function MainAsync() As Task
Dim vazifalar() As Task(Of String) = {
Ish("birinchi", 150),
Ish("ikkinchi", 50),
Ish("uchinchi", 100)
}
Dim natijalar() As String = Await Task.WhenAll(vazifalar)
Console.WriteLine(String.Join(", ", natijalar))
End Function
End Module
birinchi, ikkinchi, uchinchi
Diqqat: ikkinchi eng tez tugagan bo'lsa ham, natijalar berilgan
tartibda qaytdi. WhenAll tartibni saqlaydi - bu juda qulay.
Xatolarni ushlash #
Module Dastur
Async Function Xavfli(muvaffaqiyat As Boolean) As Task(Of Integer)
Await Task.Delay(20)
If Not muvaffaqiyat Then
Throw New InvalidOperationException("ish bajarilmadi")
End If
Return 42
End Function
Sub Main()
MainAsync().GetAwaiter().GetResult()
End Sub
Async Function MainAsync() As Task
Try
Console.WriteLine(Await Xavfli(True))
Console.WriteLine(Await Xavfli(False))
Catch ex As InvalidOperationException
Console.WriteLine($"Ushlandi: {ex.Message}")
End Try
End Function
End Module
42
Ushlandi: ish bajarilmadi
Try/Catch asinxron kodda ham odatdagidek ishlaydi - Await xatoni
o'sha joyga qaytaradi.
.Result ishlatmang #
' Yomon - dasturni qotirib qo'yishi mumkin
Dim natija As String = Tayyorlash("Choy", 100).Result
' To'g'ri
Dim natija As String = Await Tayyorlash("Choy", 100)
.Result - "shu yerda kutib tur" degani. U ishlayotgan oqimni
to'liq bloklaydi.
Konsol dasturida u ko'pincha ishlaydi. Lekin oyna interfeysi yoki veb ilovada bu klassik boshi berk ko'cha (deadlock) ga olib keladi: asosiy oqim vazifani kutadi, vazifa esa tugash uchun asosiy oqimni kutadi. Dastur butunlay qotadi.
Qoida: Await ishlating. Agar Await yoza olmayotgan bo'lsangiz,
chaqiruvchi funksiyani ham Async qiling - bu "asinxronlik yuqoriga
qarab tarqaladi" deb ataladi.
Yagona istisno - dasturning eng yuqori nuqtasi, ya'ni Sub Main.
U yerda Await yozib bo'lmaydi (yuqoridagi eslatmaga qarang) va
boshqa kutadigan hech kim yo'q, shuning uchun
MainAsync().GetAwaiter().GetResult() to'g'ri yechim hisoblanadi.
Konsol dasturida boshi berk ko'cha xavfi yo'q, chunki u yerda
SynchronizationContext mavjud emas. Oyna interfeysida esa aynan
shu qator dasturni qotirib qo'yadi.
Async Sub dan qoching #
' Yomon - xatoni ushlab bo'lmaydi
Async Sub Yuborish()
Await Task.Delay(100)
Throw New Exception("yo'qoladi")
End Sub
' To'g'ri
Async Function Yuborish() As Task
Await Task.Delay(100)
Throw New Exception("ushlash mumkin")
End Function
Async Sub qaytaradigan Task yo'q, shuning uchun uni Await
qilib bo'lmaydi va ichidagi xato hech qayerga yetib bormaydi -
u dasturni to'satdan to'xtatishi mumkin.
Yagona istisno - hodisa ishlovchilari (Button_Click kabi), chunki
ularning shakli oldindan belgilangan.
Qolgan hamma joyda Async Function ... As Task yozing.
Amaliy misol #
Imports System.IO
Module Dastur
Async Function FaylYoz(nom As String, matn As String) As Task
Await File.WriteAllTextAsync(nom, matn)
End Function
Sub Main()
MainAsync().GetAwaiter().GetResult()
End Sub
Async Function MainAsync() As Task
Dim fayllar() As String = {"a.txt", "b.txt", "c.txt"}
Dim vazifalar As New List(Of Task)
For i As Integer = 0 To fayllar.Length - 1
vazifalar.Add(FaylYoz(fayllar(i), $"Fayl raqami {i + 1}"))
Next
Await Task.WhenAll(vazifalar)
Console.WriteLine("Hamma fayl yozildi")
For Each f As String In fayllar
Console.WriteLine(Await File.ReadAllTextAsync(f))
File.Delete(f)
Next
End Function
End Module
Hamma fayl yozildi
Fayl raqami 1
Fayl raqami 2
Fayl raqami 3
.NET da ko'p metodning asinxron versiyasi bor va ular Async
qo'shimchasi bilan ataladi: ReadAllTextAsync, WriteAllTextAsync
va hokazo.
- 100 ms kutib, matn qaytaradigan
Async Functionyozing. Async Function Main() As Taskshaklini ishlating.Task(Of Integer)qaytaradigan funksiya yarating.- Uchta ishni ketma-ket
Awaitqiling va vaqtni o'lchang. - O'sha uchtasini
Task.WhenAllbilan parallel bajaring. - Natijalar tartibi berilgan tartibda qolishini tekshiring.
- Asinxron funksiyada xato ko'tarib, uni
Try/Catchbilan ushlang. Async Subyozib, xatoni ushlashga urinib ko'ring.- Uchta faylni parallel yozing.
File.ReadAllTextAsyncbilan faylni o'qing.
Xulosa #
Asyncfunksiya ichidaAwaitishlatiladi;Awaitkutadi lekin bloklamaydi.Task(Of T)qiymat qaytaradi,Taskqaytarmaydi.Async Function Main() As Task- asinxron dasturning to'g'ri boshlanishi.- Ketma-ket
Await- ishlar navbatda;Task.WhenAll- birga. WhenAllnatijalari berilgan tartibda qaytadi.Try/Catchasinxron kodda odatdagidek ishlaydi..Resultva.Wait()boshi berk ko'chaga olib boradi -Awaitishlating.Async Subxatoni yutib yuboradi -Async Function ... As Taskyozing.
Keyingi bo'limda o'rgangan hamma narsani birlashtirib, to'liq dastur yozamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.