비동기 기능을 사용하여 파일에 액세스합니다. 비동기 기능을 사용하면 콜백을 사용하거나 코드를 여러 메서드 또는 람다 식으로 분할하지 않고 비동기 메서드를 호출할 수 있습니다. 동기 코드를 비동기로 만들려면 동기 메서드 대신 비동기 메서드를 호출하고 코드에 몇 가지 키워드를 추가합니다.
다음과 같은 이유로 파일 액세스 호출에 비동기를 추가하는 것이 좋습니다.
비동기 기능을 사용하면 작업을 시작하는 UI 스레드가 다른 작업을 수행할 수 있으므로 UI 애플리케이션의 응답성이 향상됩니다. UI 스레드가 시간이 오래 걸리는 코드를 실행해야 하는 경우(예: 50밀리초 초과) I/O가 완료될 때까지 UI가 중지되고 UI 스레드가 키보드 및 마우스 입력 및 기타 이벤트를 다시 처리할 수 있습니다.
비동기에서는 스레드의 필요성을 줄여 ASP.NET 및 기타 서버 기반 애플리케이션의 확장성을 향상시킵니다. 애플리케이션이 응답당 전용 스레드를 사용하고 천 개의 요청이 동시에 처리되는 경우 1,000개의 스레드가 필요합니다. 비동기 작업은 대기 중에 스레드를 사용할 필요가 없는 경우가 많습니다. 마지막에 기존 I/O 완성 스레드를 간략하게 사용합니다.
파일 액세스 작업의 대기 시간은 현재 조건에서 매우 낮을 수 있지만 대기 시간은 나중에 크게 증가할 수 있습니다. 예를 들어 파일이 전 세계의 서버로 이동될 수 있습니다.
비동기 기능 사용 시 추가된 오버헤드는 작습니다.
호출 스레드를 차단하지 않고 여러 비동기 I/O 작업을 실행할 수 있습니다.
예제 실행
이 항목의 예제를 실행하려면 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 클래스 사용
이 항목의 예제에서는 운영 체제 수준에서 비동기 I/O를 발생시키는 옵션이 있는 클래스를 사용합니다 FileStream . 이 옵션을 사용하면 대부분의 경우 ThreadPool 스레드를 차단하지 않도록 방지할 수 있습니다. 이 옵션을 사용하려면 생성자 호출 시 useAsync=true 또는 options=FileOptions.Asynchronous 인수를 지정하십시오.
파일 경로를 지정하여 직접 여는 경우 이 옵션을 StreamReaderStreamWriter 사용할 수 없습니다. 그러나 Stream 클래스가 열어놓은 FileStream를 제공하면 이 옵션을 사용할 수 있습니다. 대기 중에 UI 스레드가 차단되지 않으므로 ThreadPool 스레드가 차단된 경우에도 UI 앱에서 비동기 호출이 더 빠릅니다.
텍스트 쓰기
다음 예제에서는 파일에 텍스트를 씁니다. 각 await 문에서 메서드는 실행을 즉시 멈춥니다. 파일 I/O가 완료되면 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가 있는 두 번째 문은 메서드를 즉시 종료하고 다른 작업을 반환합니다. 파일 처리가 완료되면 실행은 await 이후의 문장으로 돌아갑니다. 자세한 내용은 비동기 프로그램의 제어 흐름(Visual Basic)을 참조하세요.
텍스트 읽기
다음 예제에서는 파일에서 텍스트를 읽습니다. 텍스트가 버퍼링되고, 이 경우 StringBuilder에 배치됩니다. 이전 예제와 달리 await의 평가는 값을 생성합니다. 메서드는 ReadAsyncTask<Int32>를 반환하므로, 작업이 완료된 후 await의 계산이 Int32 값(numRead)을 생성합니다. 자세한 내용은 비동기 반환 형식(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
여러 비동기 I/O 작업
다음 예제에서는 여러 비동기 쓰기 작업을 시작합니다. 런타임은 이러한 작업을 큐에 대기하고, 기본 구현은 플랫폼 및 구성에 따라 운영 체제(OS) 비동기 I/O 또는 스레드 풀 스레드를 사용할 수 있으므로 실제 동시성은 OS 및 하드웨어에 따라 달라집니다. 각 파일에 대해 메서드는 WriteAsync 작업 목록에 추가되는 작업을 반환합니다. 이 문은 Await Task.WhenAll(tasks) 메서드를 종료하고 모든 작업에 대해 파일 처리가 완료되면 메서드 내에서 다시 시작됩니다.
이 예제에서는 작업이 완료된 후 블록의 FileStream 모든 Finally 인스턴스를 닫습니다. 각 FileStream이 Using 문에서 만들어졌다면, FileStream이 작업이 완료되기 전에 삭제될 수 있습니다.
비동기 접근 방식은 I/O가 보류 중인 동안 호출 스레드를 차단하지 않습니다. 대부분의 경우 처리량 향상은 OS, 하드웨어 및 일부 플랫폼에서 스레드 풀 제한 및 일정 예약과 같은 .NET 런타임 동작에 따라 달라집니다.
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를 지정하여 중간 스트림에서 작업을 취소할 수 있습니다. 자세한 내용은 귀하의 비동기 애플리케이션(Visual Basic)Fine-Tuning 및 관리 스레드에서의 취소를 참조하세요.
참고하십시오
.NET