19-bo‘lim

Asinxron dasturlash

Async va Await, Task va Task(Of T), ketma-ket va parallel bajarish, Task.WhenAll va nega .Result xavfli.

🕑 11 daqiqa o‘qish 📄 656 so‘z 👁 0 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Oddiy va asinxron
  2. Task va Task(Of T)
  3. Ketma-ket va parallel
  4. Task.WhenAll natijalari tartibi
  5. Xatolarni ushlash
  6. .Result ishlatmang
  7. Async Sub dan qoching
  8. Amaliy misol
  9. Xulosa

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 #

VB
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
Natija
Boshlandi
Choy tayyor
Tugadi

Uchta yangi so'z:

So'zMa'nosi
AsyncBu funksiya ichida Await ishlatiladi
AwaitNatijani kut, lekin bloklama
Task"Kelajakda tugaydigan ish"
Visual Basic da Async Main YO'Q

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:

Natija
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:

VB
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) #

VB
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
Natija
42
Xabar: yuborildi
  • Task(Of T) - qiymat qaytaradi (Function ga o'xshash).
  • Task - qaytarmaydi (Sub ga o'xshash).

Ketma-ket va parallel #

Mana asinxron kodning asosiy foydasi:

VB
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
Natija
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 Await oldingisini kutadi - jami ~600 ms.
  • Parallel: uchalasi birga boshlanadi - jami ~200 ms.
Nega aniq vaqt ko'rsatilmadi

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.

Uchta 200 ms lik ish Ketma-ket A - 200 ms B - 200 ms C - 200 ms 600 ms Parallel A - 200 ms B - 200 ms C - 200 ms 200 ms 0 200 400 600 ms Ishlar bir-biriga bog'liq bo'lmasa, ularni kutib o'tirish shart emas
Task.WhenAll uchta ishni birga boshlaydi va hammasini kutadi

Task.WhenAll natijalari tartibi #

VB
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
Natija
birinchi, ikkinchi, uchinchi

Diqqat: ikkinchi eng tez tugagan bo'lsa ham, natijalar berilgan tartibda qaytdi. WhenAll tartibni saqlaydi - bu juda qulay.

Xatolarni ushlash #

VB
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
Natija
42
Ushlandi: ish bajarilmadi

Try/Catch asinxron kodda ham odatdagidek ishlaydi - Await xatoni o'sha joyga qaytaradi.

.Result ishlatmang #

VB
' 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 va .Wait() boshi berk ko'chaga olib boradi

.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 #

VB
' 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 xatoni yutib yuboradi

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 #

VB
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
Natija
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.

Amaliy topshiriq
  1. 100 ms kutib, matn qaytaradigan Async Function yozing.
  2. Async Function Main() As Task shaklini ishlating.
  3. Task(Of Integer) qaytaradigan funksiya yarating.
  4. Uchta ishni ketma-ket Await qiling va vaqtni o'lchang.
  5. O'sha uchtasini Task.WhenAll bilan parallel bajaring.
  6. Natijalar tartibi berilgan tartibda qolishini tekshiring.
  7. Asinxron funksiyada xato ko'tarib, uni Try/Catch bilan ushlang.
  8. Async Sub yozib, xatoni ushlashga urinib ko'ring.
  9. Uchta faylni parallel yozing.
  10. File.ReadAllTextAsync bilan faylni o'qing.

Xulosa #

  • Async funksiya ichida Await ishlatiladi; Await kutadi lekin bloklamaydi.
  • Task(Of T) qiymat qaytaradi, Task qaytarmaydi.
  • Async Function Main() As Task - asinxron dasturning to'g'ri boshlanishi.
  • Ketma-ket Await - ishlar navbatda; Task.WhenAll - birga.
  • WhenAll natijalari berilgan tartibda qaytadi.
  • Try/Catch asinxron kodda odatdagidek ishlaydi.
  • .Result va .Wait() boshi berk ko'chaga olib boradi - Await ishlating.
  • Async Sub xatoni yutib yuboradi - Async Function ... As Task yozing.

Keyingi bo'limda o'rgangan hamma narsani birlashtirib, to'liq dastur yozamiz.

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.