비동기 기능을 사용하여 파일에 액세스할 수 있습니다. 비동기 기능을 사용하면 콜백을 사용하거나 코드를 여러 메서드 또는 람다 식으로 분할하지 않고 비동기 메서드를 호출할 수 있습니다. 동기 코드를 비동기화하려면 동기 메서드 대신 비동기 메서드를 호출하고 코드에 몇 가지 키워드를 추가하면 됩니다.
파일 액세스 호출에 비동기를 추가하는 다음 이유를 고려할 수 있습니다.
비동기 기능을 사용하면 작업을 시작하는 UI 스레드가 다른 작업을 수행할 수 있으므로 UI 애플리케이션의 응답성이 향상됩니다. UI 스레드가 시간이 오래 걸리는 코드를 실행해야 하는 경우(예: 50밀리초 초과) I/O가 완료될 때까지 UI가 중지되고 UI 스레드가 키보드 및 마우스 입력 및 기타 이벤트를 다시 처리할 수 있습니다.
비동기에서는 스레드의 필요성을 줄여 ASP.NET 및 기타 서버 기반 애플리케이션의 확장성을 향상시킵니다. 애플리케이션이 응답당 전용 스레드를 사용하고 천 개의 요청이 동시에 처리되는 경우 1,000개의 스레드가 필요합니다. 비동기 작업은 대기 중에 스레드를 사용할 필요가 없는 경우가 많습니다. 마지막에 기존 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
다음 예제에서는 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를 지정할 수 있습니다. 자세한 내용은 귀하의 비동기 애플리케이션(Visual Basic)Fine-Tuning 및 관리 스레드에서의 취소를 참조하세요.
참고하십시오
.NET