728x90
비동기적으로 파일을 처리하는 방법을 이해하기 위해 다음 단계를 수행한다.
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Chapter9.Recipe1
{
internal class Program
{
static void Main(string[] args)
{
var t = ProcessAsynchronousIO();
t.GetAwaiter().GetResult();
}
const int BUFFER_SIZE = 4096;
async static Task ProcessAsynchronousIO()
{
using (var stream = new FileStream(
"test1.txt", FileMode.Create, FileAccess.ReadWrite, FileShare.None, BUFFER_SIZE))
{
Console.WriteLine("1. Uses I/O Threads: {0}", stream.IsAsync);
byte[] buffer = Encoding.UTF8.GetBytes(CreateFileContent());
var writeTask = Task.Factory.FromAsync(
stream.BeginWrite, stream.EndWrite, buffer, 0, buffer.Length, null);
await writeTask;
}
using (var stream = new FileStream("test2.txt", FileMode.Create, FileAccess.ReadWrite,
FileShare.None, BUFFER_SIZE, FileOptions.Asynchronous))
{
Console.WriteLine("2. Uses I/O Threads: {0}", stream.IsAsync);
byte[] buffer = Encoding.UTF8.GetBytes(CreateFileContent());
var writeTask = Task.Factory.FromAsync(
stream.BeginWrite, stream.EndWrite, buffer, 0, buffer.Length, null);
await writeTask;
}
using (var stream = File.Create("test3.txt", BUFFER_SIZE, FileOptions.Asynchronous))
using (var sw = new StreamWriter(stream))
{
Console.WriteLine("3. Uses I/O Threads: {0}", stream.IsAsync);
await sw.WriteAsync(CreateFileContent());
}
using (var sw = new StreamWriter("test4.txt", true))
{
Console.WriteLine("4. Uses I/O Threads: {0}", ((FileStream)sw.BaseStream).IsAsync);
await sw.WriteAsync(CreateFileContent());
}
Console.WriteLine("Starting parsing files in parallel");
Task<long>[] readTasks = new Task<long>[4];
for (int i = 0; i < 4; i++)
{
readTasks[i] = SumFileContent(string.Format("test{0}.txt", i + 1));
}
long[] sums = await Task.WhenAll(readTasks);
Console.WriteLine("Sum in all files: {0}", sums.Sum());
Console.WriteLine("Deleting files...");
Task[] deleteTasks = new Task[4];
for (int i = 0; i < 4; i++)
{
string fileName = string.Format("test{0}.txt", i + 1);
deleteTasks[i] = SimulateAsynchronousDelete(fileName);
}
await Task.WhenAll(deleteTasks);
Console.WriteLine("Deleting complete.");
}
static string CreateFileContent()
{
var sb = new StringBuilder();
for (int i = 0; i < 100000; i++)
{
sb.AppendFormat("{0}", new Random(i).Next(0, 99999));
sb.AppendLine();
}
return sb.ToString();
}
async static Task<long> SumFileContent(string fileName)
{
using (var stream = new FileStream(fileName, FileMode.Open, FileAccess.Read,
FileShare.None, BUFFER_SIZE, FileOptions.Asynchronous))
using (var sr = new StreamReader(stream))
{
long sum = 0;
while (sr.Peek() > -1)
{
string line = await sr.ReadLineAsync();
sum += long.Parse(line);
}
return sum;
}
}
static Task SimulateAsynchronousDelete(string fileName)
{
return Task.Run(() => File.Delete(fileName));
}
}
}
결과
예제 분석
이 프로그램을 실행하면 서로 다른 방식으로 4개의 파일을 무작위 데이터로 채운다.
첫번째 경우에서는 비동기 프로그래밍 모델 API를 태스크로 변환하는 Filestream 클
래스와 메소드를 사용한다. 두 번째 경우에서는 동일하게 수행하나 Fileoptions.
Asynchronous를 FileStream 생성자에게 제공한다.
FileOptions.Asynchronous 옵션을 사용하는 것이 매우 중요하다. 이 옵션을 빼먹으면 비동기 방식으로 여전히 파일을 처리할 수 있지만, 스레드 풀에서 그냥 대리자를 호축합 뿐이다! 이 옵션(또는 재정의한 다른 생성자인 booluseAsync)을 제공할 때마FileStream 클래스로 I/O 비동기를 사용한다.
세 번째 경우에서는 File.Create 메소드와 StreamWriter 클래스 등의 몇몇 간결한
API를 사용한다. stream.IsAsync 속성을 사용해 확인할 수 있는 I/O 스레드를 여전
히 사용한다. 마지막 경우에서는 지나치게 단순화한 것도 나쁨을 보여준다. 여기서
비동기 대리자 호출의 도움으로 이것을 모방하므로 I/O 비동기를 활용할 수 없다
이제 파일을 읽어 내용을 합친 후 각각 계산을 병렬 비동기로 수행할 수 있다. 마지막
에 모든 파일을 삭제한다. 어떠한 비윈도우 스토어 애플리케이션에서는 비동기적으
로 파일을 삭제할 수 없기 때문에 Task. Run 팩토리 메소드를 사용해 비동기를 모방
한다.
728x90
'[2]SW Development Note > [2-1.2]C#' 카테고리의 다른 글
| SqlLite C.R.U.D Class (0) | 2021.05.08 |
|---|---|
| DevExpress WizardControl 사용시 유의 사항. (0) | 2021.05.04 |
| 선택된 저장장치에서 특정 확장자 검색 및 파일 액세스 거부 문제 (0) | 2021.04.29 |
| WMI Queries for Hardware Sheet (0) | 2021.01.20 |
| 스레딩 | System. Threading.Thread (0) | 2020.07.26 |
댓글