Używanie asynchronicznego dostępu do plików (Visual Basic)

Aby uzyskać dostęp do plików, możesz użyć funkcji asynchronicznego. Za pomocą funkcji asynchronicznej można wywołać metody asynchroniczne bez używania wywołań zwrotnych lub dzielenia kodu między wiele metod lub wyrażeń lambda. Aby utworzyć asynchroniczny kod synchroniczny, wystarczy wywołać metodę asynchroniczną zamiast metody synchronicznej i dodać kilka słów kluczowych do kodu.

Możesz rozważyć następujące przyczyny dodawania asynchronii do wywołań dostępu do plików:

  • Asynchrony sprawia, że aplikacje interfejsu użytkownika są bardziej dynamiczne, ponieważ wątek interfejsu użytkownika uruchamiający operację może wykonywać inne zadania. Jeśli wątek interfejsu użytkownika musi wykonywać kod, który zajmuje dużo czasu (na przykład ponad 50 milisekund), interfejs użytkownika może zamrozić do momentu ukończenia operacji we/wy, a wątek interfejsu użytkownika może ponownie przetworzyć dane wejściowe klawiatury i myszy oraz inne zdarzenia.

  • Asynchronia zwiększa skalowalność ASP.NET i innych aplikacji opartych na serwerze, zmniejszając zapotrzebowanie na wątki. Jeśli aplikacja używa dedykowanego wątku na odpowiedź, a tysiąc żądań jest obsługiwanych jednocześnie, potrzebne są tysiące wątków. Operacje asynchroniczne często nie muszą używać wątku podczas oczekiwania. Używają one istniejącego wątku uzupełniania we/wy na krótko na końcu.

  • Opóźnienie operacji dostępu do pliku może być bardzo niskie w bieżących warunkach, ale opóźnienie może znacznie wzrosnąć w przyszłości. Na przykład plik może zostać przeniesiony na serwer, który znajduje się na całym świecie.

  • Dodatkowe obciążenie związane z używaniem funkcji Async jest niewielkie.

  • Zadania asynchroniczne można łatwo uruchamiać równolegle.

Uruchamianie przykładów

Aby uruchomić przykłady w tym temacie, możesz utworzyć aplikację WPF lub aplikację Windows Forms, a następnie dodać przycisk. W zdarzeniu przycisku Click dodaj wywołanie do pierwszej metody w każdym przykładzie.

W poniższych przykładach uwzględnij następujące Imports instrukcje.

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

Korzystanie z klasy FileStream

W przykładach w tym temacie użyto FileStream klasy , która ma opcję powodującą asynchroniczne operacje we/wy na poziomie systemu operacyjnego. Korzystając z tej opcji, można uniknąć blokowania wątku ThreadPool w wielu przypadkach. Aby włączyć tę opcję, należy określić useAsync=true argument or options=FileOptions.Asynchronous w wywołaniu konstruktora.

Nie można użyć tej opcji z opcją StreamReader i StreamWriter jeśli otworzysz je bezpośrednio, określając ścieżkę pliku. Można jednak użyć tej opcji, jeśli podasz im klasę FileStream otwartąStream. Należy pamiętać, że wywołania asynchroniczne są szybsze w aplikacjach interfejsu użytkownika, nawet jeśli wątek ThreadPool jest zablokowany, ponieważ wątek interfejsu użytkownika nie jest blokowany podczas oczekiwania.

Pisanie tekstu

Poniższy przykład zapisuje tekst w pliku. W każdej instrukcji await metoda natychmiast kończy działanie. Po zakończeniu operacji we/wy pliku metoda zostanie wznowiona w instrukcji , która jest zgodna z instrukcją await. Należy pamiętać, że modyfikator asynchroniczny znajduje się w definicji metod korzystających z instrukcji await.

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  

Oryginalny przykład zawiera instrukcję Await sourceStream.WriteAsync(encodedText, 0, encodedText.Length), która jest skurczem następujących dwóch instrukcji:

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

Pierwsza instrukcja zwraca zadanie i powoduje uruchomienie przetwarzania plików. Druga instrukcja z funkcją await powoduje natychmiastowe zakończenie metody i zwrócenie innego zadania. Po zakończeniu przetwarzania pliku wykonanie powróci do instrukcji, która następuje po oczekiwaniu. Aby uzyskać więcej informacji, zobacz Przepływ sterowania w programach asynchronicznych (Visual Basic).

Odczytywanie tekstu

Poniższy przykład odczytuje tekst z pliku. Tekst jest buforowany i w tym przypadku umieszczany w obiekcie StringBuilder. W przeciwieństwie do poprzedniego przykładu ocena oczekiwania generuje wartość. Metoda ReadAsync zwracaInt32<>Task wartość , więc ocena oczekiwania generuje Int32 wartość (numRead) po zakończeniu operacji. Aby uzyskać więcej informacji, zobacz Async Return Types (Visual Basic).

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  

Równoległe asynchroniczne operacje we/wy

W poniższym przykładzie pokazano przetwarzanie równoległe przez zapisanie 10 plików tekstowych. Dla każdego pliku WriteAsync metoda zwraca zadanie, które jest następnie dodawane do listy zadań. Instrukcja Await Task.WhenAll(tasks) kończy działanie metody i wznawia działanie metody podczas przetwarzania plików dla wszystkich zadań podrzędnych.

Przykład zamyka wszystkie FileStream wystąpienia w Finally bloku po zakończeniu zadań. Jeśli każda z nich FileStream została utworzona w instrukcji Imports , FileStream element może zostać usunięty przed ukończeniem zadania.

Należy pamiętać, że każdy wzrost wydajności jest prawie całkowicie z przetwarzania równoległego, a nie z przetwarzania asynchronicznego. Zalety asynchronicznego to to, że nie jest on wiązany z wieloma wątkami i że nie jest on wiązany z wątkiem interfejsu użytkownika.

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  

W przypadku korzystania z WriteAsync metod i ReadAsync można określić CancellationTokenelement , którego można użyć do anulowania operacji w połowie strumienia. Aby uzyskać więcej informacji, zobacz Dostosowywanie aplikacji asynchronicznych (Visual Basic) i anulowanie w zarządzanych wątkach.

Zobacz też