Partilhar via


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.

Consulte também