static void Main(string [] args)
{
using (FileStream fs = new FileStream("...",
FileMode.Open, File.Access.Read, FileShare.ReadWrite)) //파일 객체 생성
{
byte[] buf = new byte[fs.Length];
fs.Read(buf, 0, buf.Length);
string txt = Encoding.UTF8.GetString(buf);
Console.WriteLine(txt);
}
}
Read 메서드를 완료한 후 파일의 내용을 화면에 출력하는 코드를 순차적으로 실행한다.기존의 비동기 방식
private static void AsyncRead()
{
FileStream fs = new Filestream("...", FileMode.Open, File.Access.Read, FileShare.ReadWrite);
FileState state = new FileState();
state.Buffer = new byte[fs.Length];
state.File = fs;
fs.BeginRead(state.Buffer, 0, sate.Buffer.Length, readCompleted, state);
//Read가 완료된 후의 코드를 readCompleted로 넘겨서 처리한다.
Console.ReadLine();
fs.Close();
}
BeginRead 메서드를 호출했을 때 Read 동작 이후의 코드를 별도로 분리해 readCompleted 메서드를static void readCompleted(IAsyncResult ar)
{
FileState state = ar.AsyncState as FileState;
state.File.EndRead(ar);
string txt = Encoding.UTF8.GetString(state.Buffer);
Console.WriteLine(txt);
}
읽기 작업이 완료되면 스레드 풀의 자유 스레드가 readCompleted 메서드를 실행시킨다.
동기 방식을 비동기 방식으로 바꾸기 위해서는 Read 호출 이후의 코드를 BeginRead에 전달한다. (콜백)
C#에서 지원하는 비동기 방식
Read호출 이후의 코드를 따로 전달하는 번거로움을 없앤다.
async await 키워드를 사용한다.async : 해당 메서드가 비동기 작업을 수행할 수 있음을 명시한다.await : 비동기 작업의 완료를 기다린 후 다음 코드를 실행하게 만든다. 이로 인해 프로그램이 중지되지 않고 비동기로 동작할 수 있다.private static async void AwaitRead()
{
using (FileStream fs = new FileStream("...", FileMode.Open, File.Access.Read, FileShare.ReadWrite)) //파일 객체 생성
{
byte[] buf = new byte[fs.Length]; //파일 크기만큼의 바이트 배열 생성
Console.WriteLine("Before ReadAsync: " + Thread.CurrentThread.ManagedThreadId);
//---------------------------------------------------------------------------//
await fs.ReadAsync(buf, 0, buf.Length);
Console.WriteLine("After ReadAsync: " + Thread.CurrentThread.ManagedThreadId);
string txt = Encoding.UTF8.GetString(buf);
Console.WriteLine(txt);
}
}
await 이후의 코드를 묶어서 ReadAsync의 비동기 호출이 끝난 후 실행되도록 한다.await 뒤의 코드가 실행된다.ReadAsync가 완료되면, "After ReadAsync : " 문장이 출력되고,① 동기 방식
- 한 줄의 코드가 끝날때까지 다음 코드로 넘어가지 않는다.
WebClient wc = new WebClient();
string txt = wc.DownloadString(" ... ");
Console.WriteLine(txt);
wc.DownloadString(" ... ");, 웹 페이지에서 문자열을 다운로드 할 때까지 프로그램이 멈춘다.Console.WriteLine(txt);)를 실행한다.② 비동기 방식
- 시간이 오래 걸리는 작업(ex.파일 다운로드, 네트워크 요청 등)이 수행되는 동안 메인 스레드가 해당 작업을 기다리지 않고 다른 작업을 계속 진행할 수 있다.
- 작업이 진행되는 동안 다른 작업을 병렬로 수행할 수 있다.
- 특정 작업이 완료될 때까지 프로그램의 실행을 멈추지 않는다.
Callback 함수를 호출하여 프로그램이 멈추거나 응답하지 않는 문제를 방지한다.static void Main(string [] args)
{
WebClient wc = new WebClient(); //객체 생성
//이벤트 핸들러 함수 (콜백)
wc.DownloadStringCompleted += wc_DownloadStringCompleted;
//비동기적으로 문자열 다운로드
wc.DownloadStringAsync(new Uri(" ..." );
Console.ReadLine();
}
static void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
//다운로드된 HTML 텍스트 출력
Console.WriteLine(e.Result);
}
위 코드는 콜백 기반의 비동기 프로그램이다.
이벤트 핸들러를 통해 비동기 작업 완료 시 호출될 메서드를 등록한다. (함수 실행 완료를 통지한다.)
프로그램의 주 실행 흐름이 멈추지 않고 다른 작업을 계속할 수 있다.
③ async / await 키워드를 사용한 비동기 방식
static void Main(string [] args)
{
AwaitDownloadString(); //비동기 메서드 호출
Console.ReadLine(); //사용자가 엔터를 누를 때까지 대기
}
private static async void AwaitDownloadString()
{
WebClient wc = new WebClient(); //객체 생성
string text = await wc.DownloadStringTaskAsync(" ... "); //비동기 작업 대기
Console.WriteLine(text); //다운로드 완료 후 텍스트 출력
}
AwaitDownloadString()은 비동기 메서드이므로 즉시 반환된다. (메인 스레드는 멈추지 X)
wc.DownloadStringTaskAsync(" ... "); 네트워크에서 데이터를 다운로드 하는 비동기 작업을 수행한다.
await는 작업이 완료될 때까지 기다리지만 메인 스레드는 대기하지 않고 자유롭게 다른 작업을 수행할 수 있다.
다운로드가 완료되면 Console.WriteLine(text)가 실행된다. 다운로드가 끝날 때까지 기다렸다가 텍스트를 출력한다.