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

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

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

  • Asynchronia sprawia, że aplikacje interfejsu użytkownika są bardziej dynamiczne, ponieważ wątek interfejsu użytkownika, który uruchamia 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 więcej niż 50 milisekund), interfejs użytkownika może się zablokować 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 potrzebę wątków. Jeśli aplikacja używa dedykowanego wątku na odpowiedź, a tysiące żądań jest obsługiwanych jednocześnie, potrzebnych jest tysiąc wątków. Operacje asynchroniczne często nie muszą używać wątku podczas oczekiwania. Używają one istniejącego wątku ukończenia we/wy na krótko na końcu.

  • W bieżących warunkach opóźnienie operacji dostępu do plików może być bardzo małe, ale w przyszłości może znacznie wzrosnąć. Na przykład plik można przenieść na serwer, który jest na całym świecie.

  • Dodatkowe obciążenie związane z używaniem funkcji asynchronicznej 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 Click przycisku 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

Przykłady w tym temacie używają klasy , która ma opcję, która powoduje, że asynchroniczne operacje FileStream we/wy występują 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 options=FileOptions.Asynchronous argument lub w wywołaniu konstruktora.

Nie można użyć tej opcji z i jeśli otworzysz je StreamReader StreamWriter bezpośrednio, określając ścieżkę pliku. Można jednak użyć tej opcji, jeśli udostępnisz im Stream klasę FileStream otwartą. 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 do pliku. W każdej instrukcji await metoda natychmiast kończy działanie. Po zakończeniu we/wy pliku metoda wznawia działanie w instrukcji , która następuje po instrukcji await. Należy pamiętać, że modyfikator asynchroniczny znajduje się w definicji metod, które używają 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 instrukcje Await sourceStream.WriteAsync(encodedText, 0, encodedText.Length) , które są zaostrzeniami 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 await powoduje natychmiastowe zakończenie metody i zwrócenie innego zadania. Po późniejszym zakończeniu przetwarzania plików wykonywanie powraca do instrukcji , która następuje po instrukcji await. Aby uzyskać więcej informacji, zobacz Control Flow in Async Programs (Visual Basic).

Odczytywanie tekstu

Poniższy przykład odczytuje tekst z pliku. Tekst jest buforowany i w tym przypadku umieszczany w StringBuilder . W przeciwieństwie do poprzedniego przykładu, ocena await generuje wartość. Metoda zwraca>, więc ocena await generuje wartość ReadAsync Task <Int32 ( ) Int32 po numRead zakończeniu operacji. Aby uzyskać więcej informacji, zobacz Asynchroniczne typy zwracane (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 napisanie 10 plików tekstowych. Dla każdego pliku metoda WriteAsync zwraca zadanie, które jest następnie dodawane do listy zadań. Instrukcja kończy działanie metody i wznawia działanie w ramach metody po zakończeniu przetwarzania plików Await Task.WhenAll(tasks) dla wszystkich zadań.

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

Należy pamiętać, że każdy wzrost wydajności pochodzi niemal całkowicie z przetwarzania równoległego, a nie przetwarzania asynchronicznego. Zaletą synchronizacji jest to, że nie wiąże ona wielu wątków i nie wiąże wątku 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 metod i można określić , za pomocą którego można WriteAsync ReadAsync CancellationToken anulować operację w połowie strumienia. Aby uzyskać więcej informacji, zobacz Dostrajanie aplikacji asynchronicznej (Visual Basic) i Anulowanie w zarządzanych wątkach.

Zobacz też