Použití Async pro přístup k souborům (Visual Basic)
K přístupu k souborům můžete použít funkci Async. Pomocí funkce Async můžete volat asynchronní metody bez použití zpětného volání nebo rozdělení kódu mezi více metod nebo výrazů lambda. Pokud chcete, aby synchronní kód byl asynchronní, stačí místo synchronní metody volat asynchronní metodu a přidat do kódu několik klíčových slov.
Můžete zvážit následující důvody přidání asynchrony do volání přístupu k souborům:
Asynchrony zvyšuje odezvu aplikací uživatelského rozhraní, protože vlákno uživatelského rozhraní, které spouští operaci, může provádět jinou práci. Pokud vlákno uživatelského rozhraní musí spouštět kód, který trvá dlouhou dobu (například více než 50 milisekund), uživatelské rozhraní se může ukotvit, dokud se vstupně-výstupní operace nezačne dokončit a vlákno uživatelského rozhraní může znovu zpracovat vstup klávesnice a myš a další události.
Asynchrony zlepšuje škálovatelnost ASP.NET a dalších serverových aplikací tím, že snižuje potřebu vláken. Pokud aplikace používá vyhrazené vlákno na odpověď a současně zpracovává tisíce požadavků, je potřeba tisíc vláken. Asynchronní operace často nemusí během čekání používat vlákno. Použijí existující vlákno pro doplňování vstupně-výstupních operací krátce na konci.
Latence operace přístupu k souboru může být za aktuálních podmínek velmi nízká, ale latence se může v budoucnu výrazně zvýšit. Soubor se například může přesunout na server, který je po celém světě.
Přidaná režie při používání funkce Async je malá.
Asynchronní úlohy je možné snadno spustit paralelně.
Spuštění příkladů
Pokud chcete spustit příklady v tomto tématu, můžete vytvořit aplikaci WPF nebo aplikaci model Windows Forms a pak přidat tlačítko. V události tlačítka Click
přidejte volání první metody v každém příkladu.
V následujících příkladech uveďte následující Imports
příkazy.
Imports System
Imports System.Collections.Generic
Imports System.Diagnostics
Imports System.IO
Imports System.Text
Imports System.Threading.Tasks
Použití třídy FileStream
Příklady v tomto tématu používají FileStream třídu, která má možnost, která způsobuje, že asynchronní vstupně-výstupní operace na úrovni operačního systému. Pomocí této možnosti se můžete vyhnout blokování vlákna ThreadPool v mnoha případech. Chcete-li tuto možnost povolit, zadáte useAsync=true
hodnotu nebo options=FileOptions.Asynchronous
argument ve volání konstruktoru.
Tuto možnost StreamReader nemůžete použít a StreamWriter pokud je otevřete přímo zadáním cesty k souboru. Tuto možnost však můžete použít, pokud jim Stream zadáte, že FileStream byla třída otevřena. Všimněte si, že asynchronní volání jsou v aplikacích uživatelského rozhraní rychlejší, i když je vlákno ThreadPool blokováno, protože vlákno uživatelského rozhraní není během čekání blokováno.
Psaní textu
Následující příklad zapíše text do souboru. V každém příkazu await metoda okamžitě ukončí. Po dokončení vstupně-výstupních operací se metoda obnoví v příkazu, který následuje za příkazem await. Všimněte si, že modifikátor async je v definici metod, které používají příkaz 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
Původní příklad obsahuje příkaz Await sourceStream.WriteAsync(encodedText, 0, encodedText.Length)
, což je kontrakt následujících dvou příkazů:
Dim theTask As Task = sourceStream.WriteAsync(encodedText, 0, encodedText.Length)
Await theTask
První příkaz vrátí úlohu a způsobí spuštění zpracování souborů. Druhý příkaz s příkazem await způsobí, že metoda okamžitě ukončí a vrátí jiný úkol. Po dokončení zpracování souboru se spuštění vrátí do příkazu, který následuje za příkazem await. Další informace naleznete v tématu Tok řízení v asynchronních programech (Visual Basic).
Čtení textu
Následující příklad načte text ze souboru. Text je uložen do vyrovnávací paměti a v tomto případě je umístěn do .StringBuilder Na rozdíl od předchozího příkladu vytvoří vyhodnocení operátoru await hodnotu. Metoda ReadAsync vrátí hodnotuInt32<>Task , takže vyhodnocení await vytvoří Int32
hodnotu (numRead
) po dokončení operace. Další informace naleznete v tématu Asynchronní návratové typy (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
Paralelní asynchronní vstupně-výstupní operace
Následující příklad ukazuje paralelní zpracování zápisem 10 textových souborů. Pro každý soubor WriteAsync vrátí metoda úkol, který se pak přidá do seznamu úkolů. Příkaz Await Task.WhenAll(tasks)
ukončí metodu a obnoví v rámci metody, když je zpracování souboru dokončeno pro všechny úlohy.
Příklad po dokončení úkolů zavře všechny FileStream instance v Finally
bloku. Pokud se každý z nich FileStream
vytvořil v Imports
příkazu, FileStream
může být uvolněn před dokončením úkolu.
Všimněte si, že zvýšení výkonu téměř zcela pochází z paralelního zpracování, nikoli asynchronního zpracování. Výhodou asynchrony je, že neváže více vláken a že neváže vlákno uživatelského rozhraní.
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
Při použití a WriteAsyncReadAsync metod můžete zadat CancellationToken, který můžete použít ke zrušení operace uprostřed datového proudu. Další informace najdete v tématu Vyladění asynchronní aplikace (Visual Basic) a zrušení ve spravovaných vláknech.