Usando o Async para acesso a arquivos (Visual Basic)
Você pode usar o recurso Assíncrono para acessar arquivos. Usando o recurso Assíncrono, você pode chamar métodos assíncronos sem usar retornos de chamada ou dividir seu código em vários métodos ou expressões lambda. Para tornar o código síncrono assíncrono, basta chamar um método assíncrono em vez de um método síncrono e adicionar algumas palavras-chave ao código.
Você pode considerar os seguintes motivos para adicionar assincronia às chamadas de acesso a arquivos:
A assincronia torna os aplicativos da interface do usuário mais responsivos porque o thread da interface do usuário que inicia a operação pode executar outro trabalho. Se o thread da interface do usuário precisar executar um código que leva muito tempo (por exemplo, mais de 50 milissegundos), a interface do usuário poderá congelar até que a E/S seja concluída e o thread da interface do usuário possa processar novamente a entrada do teclado e do mouse e outros eventos.
A assincronia melhora a escalabilidade de ASP.NET e outros aplicativos baseados em servidor, reduzindo a necessidade de threads. Se o aplicativo usa um thread dedicado por resposta e mil solicitações estão sendo tratadas simultaneamente, mil threads são necessários. As operações assíncronas geralmente não precisam usar um thread durante a espera. Eles usam o thread de conclusão de E/S existente brevemente no final.
A latência de uma operação de acesso a arquivos pode ser muito baixa nas condições atuais, mas a latência pode aumentar muito no futuro. Por exemplo, um arquivo pode ser movido para um servidor que está em todo o mundo.
A sobrecarga adicional de usar o recurso assíncrono é pequena.
As tarefas assíncronas podem ser facilmente executadas em paralelo.
Executando os exemplos
Para executar os exemplos neste tópico, você pode criar um aplicativo WPF ou um aplicativo Windows Forms e, em seguida, adicionar um botão. No evento do Click
botão, adicione uma chamada ao primeiro método em cada exemplo.
Nos exemplos a seguir, inclua as instruções a seguir Imports
.
Imports System
Imports System.Collections.Generic
Imports System.Diagnostics
Imports System.IO
Imports System.Text
Imports System.Threading.Tasks
Uso da classe FileStream
Os exemplos neste tópico usam a FileStream classe, que tem uma opção que faz com que a E/S assíncrona ocorra no nível do sistema operacional. Usando essa opção, você pode evitar bloquear um thread ThreadPool em muitos casos. Para habilitar essa opção, especifique o useAsync=true
argumento ou options=FileOptions.Asynchronous
na chamada do construtor.
Você não pode usar essa opção com StreamReader e StreamWriter se abri-los diretamente especificando um caminho de arquivo. No entanto, você pode usar essa opção se fornecer a eles um Stream que a FileStream classe abriu. Observe que as chamadas assíncronas são mais rápidas em aplicativos de interface do usuário, mesmo que um thread ThreadPool esteja bloqueado, porque o thread da interface do usuário não é bloqueado durante a espera.
Escrever texto
O exemplo a seguir grava texto em um arquivo. A cada instrução await, o método é encerrado imediatamente. Quando a E/S do arquivo estiver concluída, o método será retomado na instrução que segue a instrução await. Observe que o modificador async está na definição de métodos que usam a instrução 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
O exemplo original tem a afirmação Await sourceStream.WriteAsync(encodedText, 0, encodedText.Length)
, que é uma contração das duas afirmações a seguir:
Dim theTask As Task = sourceStream.WriteAsync(encodedText, 0, encodedText.Length)
Await theTask
A primeira instrução retorna uma tarefa e faz com que o processamento do arquivo seja iniciado. A segunda instrução com o await faz com que o método saia imediatamente e retorne uma tarefa diferente. Quando o processamento do arquivo for concluído posteriormente, a execução retornará à instrução que segue a espera. Para obter mais informações, consulte Fluxo de controle em programas assíncronos (Visual Basic).
Leitura de Texto
O exemplo a seguir lê o texto de um arquivo. O texto é armazenado em buffer e, neste caso, colocado em um StringBuilderarquivo . Ao contrário do exemplo anterior, a avaliação da espera produz um valor. O ReadAsync método retorna um Task<>Int32, de modo que a avaliação do await produz um Int32
valor (numRead
) após a conclusão da operação. Para obter mais informações, consulte Tipos de retorno assíncronos (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
E/S assíncronas paralelas
O exemplo a seguir demonstra o processamento paralelo gravando 10 arquivos de texto. Para cada arquivo, o WriteAsync método retorna uma tarefa que é adicionada a uma lista de tarefas. A Await Task.WhenAll(tasks)
instrução sai do método e é retomada dentro do método quando o processamento do arquivo é concluído para todas as tarefas.
O exemplo fecha todas as FileStream instâncias em um Finally
bloco após a conclusão das tarefas. Se, em vez disso, cada FileStream
um foi criado em uma Imports
instrução, o FileStream
pode ser descartado antes que a tarefa seja concluída.
Observe que qualquer aumento de desempenho é quase inteiramente do processamento paralelo e não do processamento assíncrono. As vantagens da assincronia são que ela não amarra vários threads e não amarra o thread da interface do usuário.
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
Ao usar os WriteAsync métodos and ReadAsync , você pode especificar um CancellationToken, que pode ser usado para cancelar a operação mid-stream. Para obter mais informações, consulte Ajustando seu aplicativo assíncrono (Visual Basic) e Cancelamento em threads gerenciados.