Поделиться через


Использование async для доступа к файлам (Visual Basic)

Для доступа к файлам можно использовать функцию Async. С помощью функции Async можно вызывать асинхронные методы без использования обратных вызовов или разделения кода по нескольким методам или лямбда-выражениям. Чтобы сделать синхронный код асинхронным, просто вызовите асинхронный метод вместо синхронного метода и добавьте несколько ключевых слов в код.

Вы можете рассмотреть следующие причины добавления асинхронности в вызовы доступа к файлам:

  • Asynchrony повышает скорость реагирования приложений пользовательского интерфейса, так как поток пользовательского интерфейса, запускающий операцию, может выполнять другую работу. Если поток пользовательского интерфейса должен выполнять код, который занимает много времени (например, более 50 миллисекунд), пользовательский интерфейс может заморозить до завершения ввода-вывода, а поток пользовательского интерфейса может снова обрабатывать ввод клавиатуры и мыши и другие события.

  • Асинхронность повышает масштабируемость ASP.NET и других серверных приложений, уменьшая потребность в потоках. Если приложение использует выделенный поток для каждого ответа и тысячи запросов обрабатываются одновременно, требуются тысячи потоков. Асинхронные операции часто не требуют использования потока во время ожидания. Они используют существующий поток завершения ввода-вывода кратко в конце.

  • Задержка операции доступа к файлам может быть очень низкой в текущих условиях, но задержка может значительно увеличиться в будущем. Например, файл может быть перемещен на сервер, который находится по всему миру.

  • Дополнительные затраты на использование функции Async невелики.

  • Асинхронные задачи можно легко выполнять параллельно.

Запуск примеров

Чтобы выполнить примеры в этом разделе, можно создать приложение WPF или приложение Windows Forms , а затем добавить кнопку. В событии кнопки Click добавьте вызов первого метода в каждом примере.

В следующих примерах включите следующие Imports инструкции.

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

Использование класса FileStream

В примерах этого раздела используется FileStream класс, который имеет параметр, который приводит к возникновению асинхронного ввода-вывода на уровне операционной системы. С помощью этого параметра можно избежать блокировки потока ThreadPool во многих случаях. Чтобы включить этот параметр, необходимо указать аргумент useAsync=true или options=FileOptions.Asynchronous в вызове конструктора.

Этот параметр нельзя использовать с StreamReader и StreamWriter, если вы открываете их напрямую, указав путь к файлу. Однако этот параметр можно использовать, если предоставить им Stream, который был открыт классом FileStream. Обратите внимание, что асинхронные вызовы быстрее используются в приложениях пользовательского интерфейса, даже если поток ThreadPool заблокирован, так как поток пользовательского интерфейса не блокируется во время ожидания.

Написание текста

В следующем примере записывается текст в файл. В каждой инструкции await метод немедленно завершает работу. После завершения ввода-вывода файла метод возобновляется в инструкции, следующей за инструкцией await. Обратите внимание, что асинхронный модификатор находится в определении методов, использующих инструкцию 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  

В исходном примере имеется выражение Await sourceStream.WriteAsync(encodedText, 0, encodedText.Length), которое является сокращением следующих двух операторов.

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

Первая инструкция возвращает задачу и приводит к началу обработки файлов. Вторая инструкция с await приводит к тому, что метод немедленно завершает работу и возвращает другую задачу. После завершения обработки файлов выполнение возвращается в инструкцию, которая следует за ожиданием. Дополнительные сведения см. в разделе "Поток управления" в асинхронных программах (Visual Basic).

Чтение текста

В следующем примере считывается текст из файла. Текст буферичен и, в данном случае, помещается в объект StringBuilder. В отличие от предыдущего примера, оценка await создает значение. Метод ReadAsync возвращает Task<Int32>, поэтому выполнение await приводит к тому, что выдается Int32 значение (numRead) после завершения операции. Дополнительные сведения см. в статье 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  

Параллельный асинхронный ввод-вывод

В следующем примере демонстрируется параллельная обработка путем записи 10 текстовых файлов. Для каждого файла WriteAsync метод возвращает задачу, которая затем добавляется в список задач. Оператор Await Task.WhenAll(tasks) завершает метод и возобновляет работу в методе при завершении обработки файлов для всех задач.

Пример закрывает все FileStream инстанции в блоке Finally после завершения задач. Если FileStream был создан в операторе Imports, FileStream могло быть уничтожено до завершения задачи.

Обратите внимание, что любое повышение производительности почти полностью происходит от параллельной обработки, а не асинхронной обработки. Преимущества асинхронности заключается в том, что он не связывает несколько потоков, и что он не связывает поток пользовательского интерфейса.

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  

При использовании WriteAsync и ReadAsync методов можно указать CancellationToken, который можно использовать для отмены операции в середине потока. Дополнительные сведения см. в Fine-Tuning Асинхронное приложение (Visual Basic) и Отмена в управляемых потоках.

См. также