Async gebruiken voor Bestandstoegang (Visual Basic)

Gebruik de functie Async om toegang te krijgen tot bestanden. Met behulp van de functie Async kunt u asynchrone methoden aanroepen zonder callbacks te gebruiken of uw code over meerdere methoden of lambda-expressies te splitsen. Als u synchrone code asynchroon wilt maken, roept u een asynchrone methode aan in plaats van een synchrone methode en voegt u enkele trefwoorden toe aan de code.

Overweeg om, om deze redenen, asynchronie toe te voegen aan aanroepen voor bestandstoegang.

  • Asynchrony maakt UI-toepassingen responsiefer omdat de UI-thread waarmee de bewerking wordt gestart, ander werk kan uitvoeren. Als de UI-thread code moet uitvoeren die lang duurt (bijvoorbeeld meer dan 50 milliseconden), wordt de gebruikersinterface mogelijk geblokkeerd totdat de I/O is voltooid en kan de UI-thread opnieuw toetsenbord- en muisinvoer en andere gebeurtenissen verwerken.

  • Asynchroon verbetert de schaalbaarheid van ASP.NET en andere servertoepassingen door de noodzaak van threads te verminderen. Als de toepassing een toegewezen thread per antwoord gebruikt en duizend aanvragen tegelijkertijd worden verwerkt, zijn er duizend threads nodig. Asynchrone bewerkingen hoeven vaak geen thread te gebruiken tijdens de wachttijd. Ze gebruiken aan het einde kort de bestaande I/O-afhandelingsdraad.

  • De latentie van een bestandstoegangsbewerking kan erg laag zijn onder de huidige omstandigheden, maar de latentie kan in de toekomst aanzienlijk toenemen. Een bestand kan bijvoorbeeld worden verplaatst naar een server over de hele wereld.

  • De extra overhead voor het gebruik van de Async-functie is klein.

  • Meerdere asynchrone I/O-bewerkingen kunnen worden uitgevoerd zonder de aanroepende thread te blokkeren.

De voorbeelden uitvoeren

Als u de voorbeelden in dit onderwerp wilt uitvoeren, maakt u een WPF-toepassing of een Windows Forms-toepassing en voegt u vervolgens een knop toe. Voeg in de Click gebeurtenis van de knop een aanroep naar de eerste methode toe in elk voorbeeld.

"Neem in de volgende voorbeelden de volgende Imports uitspraken op."

Imports System
Imports System.Collections.Generic
Imports System.Diagnostics
Imports System.IO
Imports System.Text
Imports System.Threading.Tasks

Gebruik van de Klasse FileStream

In de voorbeelden in dit onderwerp wordt de FileStream klasse gebruikt, die een optie heeft die ervoor zorgt dat asynchrone I/O op besturingssysteemniveau plaatsvindt. Met deze optie kunt u voorkomen dat een ThreadPool-thread in veel gevallen wordt geblokkeerd. Als u deze optie wilt inschakelen, geeft u het useAsync=true of options=FileOptions.Asynchronous argument op in de constructor-aanroep.

U kunt deze optie niet gebruiken met StreamReader en StreamWriter als u ze rechtstreeks opent door een bestandspad op te geven. U kunt deze optie echter gebruiken als u een Stream opgeeft dat de FileStream-klasse geopend is. Asynchrone aanroepen zijn sneller in UI-apps, zelfs als een ThreadPool-thread is geblokkeerd, omdat de UI-thread tijdens de wachttijd niet wordt geblokkeerd.

Tekst schrijven

In het volgende voorbeeld wordt tekst naar een bestand geschreven. Bij elke await-instructie wordt de methode onmiddellijk afgesloten. Wanneer de bestands-I/O is voltooid, wordt de methode hervat bij de instructie die volgt op de await-instructie. De async-modifier wordt gebruikt in de definitie van methodes die de await-instructie gebruiken.

Public Async Sub ProcessWrite()
    Dim filePath = "temp2.txt"
    Dim text = "Hello World" & ControlChars.CrLf

    Await WriteTextAsync(filePath, text)
End Sub

Private Async Function WriteTextAsync(filePath As String, text As String) As Task
    Dim encodedText As Byte() = Encoding.Unicode.GetBytes(text)

    Using sourceStream As New FileStream(filePath,
        FileMode.Append, FileAccess.Write, FileShare.None,
        bufferSize:=4096, useAsync:=True)

        Await sourceStream.WriteAsync(encodedText, 0, encodedText.Length)
    End Using
End Function

Het oorspronkelijke voorbeeld heeft de instructie Await sourceStream.WriteAsync(encodedText, 0, encodedText.Length), een samentrekking van de volgende twee instructies:

Dim theTask As Task = sourceStream.WriteAsync(encodedText, 0, encodedText.Length)
Await theTask

De eerste instructie retourneert een taak en zorgt ervoor dat bestandsverwerking wordt gestart. De tweede instructie met await zorgt ervoor dat de methode onmiddellijk stopt en een andere taak retourneert. Wanneer de bestandsverwerking later voltooid is, keert de uitvoering terug naar de instructie die volgt op de await. Zie Controlestroom in Async-programma's (Visual Basic) voor meer informatie.

Tekst lezen

In het volgende voorbeeld wordt tekst uit een bestand gelezen. De tekst wordt gebufferd en in dit geval wordt het geplaatst in een StringBuilder. In tegenstelling tot in het vorige voorbeeld produceert de evaluatie van de await een waarde. De ReadAsync methode retourneert een Task<Int32>, zodat de evaluatie van de await een Int32 waarde (numRead) produceert nadat de bewerking is voltooid. Zie Asynchrone retourtypen (Visual Basic) voor meer informatie.

Public Async Sub ProcessRead()
    Dim filePath = "temp2.txt"

    If File.Exists(filePath) = False Then
        Debug.WriteLine("file not found: " & filePath)
    Else
        Try
            Dim text As String = Await ReadTextAsync(filePath)
            Debug.WriteLine(text)
        Catch ex As Exception
            Debug.WriteLine(ex.Message)
        End Try
    End If
End Sub

Private Async Function ReadTextAsync(filePath As String) As Task(Of String)

    Using sourceStream As New FileStream(filePath,
        FileMode.Open, FileAccess.Read, FileShare.Read,
        bufferSize:=4096, useAsync:=True)

        Dim sb As New StringBuilder

        Dim buffer As Byte() = New Byte(&H1000) {}
        Dim numRead As Integer
        numRead = Await sourceStream.ReadAsync(buffer, 0, buffer.Length)
        While numRead <> 0
            Dim text As String = Encoding.Unicode.GetString(buffer, 0, numRead)
            sb.Append(text)

            numRead = Await sourceStream.ReadAsync(buffer, 0, buffer.Length)
        End While

        Return sb.ToString
    End Using
End Function

Meerdere asynchrone I/O-bewerkingen

In het volgende voorbeeld worden meerdere asynchrone schrijfbewerkingen gestart. De runtime plaatst deze bewerkingen in wachtrijen, en de onderliggende implementatie kan, afhankelijk van het platform en de configuratie, gebruikmaken van asynchrone I/O of threadpoolthreads van het besturingssysteem (OS). Daardoor is de daadwerkelijke gelijktijdigheid afhankelijk van het besturingssysteem en de hardware. Voor elk bestand retourneert de WriteAsync methode een taak die wordt toegevoegd aan een lijst met taken. De Await Task.WhenAll(tasks) instructie beëindigt de methode en hervat de uitvoering binnen de methode wanneer de bestandsverwerking voor alle taken is voltooid.

In het voorbeeld worden alle FileStream exemplaren in een Finally blok gesloten nadat de taken zijn voltooid. Als elk FileStream in plaats daarvan in een Using instructie is gemaakt, kan het FileStream worden verwijderd voordat de taak is voltooid.

De asynchrone benadering voorkomt dat de oproepende thread wordt geblokkeerd terwijl de I/O nog in afwachting is. In veel gevallen zijn doorvoerverbeteringen afhankelijk van het besturingssysteem, de hardware en, op sommige platforms, .NET-runtimegedrag, zoals limieten voor threadpools en planning.

Public Async Sub ProcessWriteMult()
    Dim folder = "tempfolder\"
    Dim tasks As New List(Of Task)
    Dim sourceStreams As New List(Of FileStream)

    Try
        For index = 1 To 10
            Dim text = "In file " & index.ToString & ControlChars.CrLf

            Dim fileName = "thefile" & index.ToString("00") & ".txt"
            Dim filePath = folder & fileName

            Dim encodedText As Byte() = Encoding.Unicode.GetBytes(text)

            Dim sourceStream As New FileStream(filePath,
                FileMode.Append, FileAccess.Write, FileShare.None,
                bufferSize:=4096, useAsync:=True)

            Dim theTask As Task = sourceStream.WriteAsync(encodedText, 0, encodedText.Length)
            sourceStreams.Add(sourceStream)

            tasks.Add(theTask)
        Next

        Await Task.WhenAll(tasks)
    Finally
        For Each sourceStream As FileStream In sourceStreams
            sourceStream.Close()
        Next
    End Try
End Sub

Wanneer u de WriteAsync en ReadAsync methoden gebruikt, kunt u een CancellationToken opdracht opgeven om de bewerking halverwege de stream te annuleren. Zie Fine-Tuning Uw asynchrone toepassing (Visual Basic) en annulering in Beheerde threads voor meer informatie.

Zie ook