Programming/.NET

특정 메서드의 비동기 호출을 시도할때는 대부분 작업을 진행하는 메서드부분과 작업을 완료하고 호출되는 메서드를 스레드로 분리하면서 이루어집니다. 하지만 async / await 를 사용하면 비동기호출시 완료처리를 위해 추가했던 별도의 메서드를 분리할 필요가 없어집니다.

 

using (FileStream fs = new FileStream(@"C:\\test.txt"FileMode.OpenFileAccess.ReadFileShare.Read)) {
    byte[] b = new byte[fs.Length];
    fs.Read(b, 0, b.Length);

    string s = Encoding.UTF8.GetString(b);
}

 

이 예제는 FileStream을 통해 파일 내용을 읽어들이는 동기식 방법입니다. 이 예제를 async / await 가 없을때 비동기식으로 바꾸면 다음과 같이 할 수 있습니다.

 

static byte[] b;
static void Main(string[] args)
{
    FileStream fs = new FileStream("test.txt"FileMode.OpenFileAccess.ReadFileShare.Read);
    b = new byte[fs.Length];
    fs.BeginRead(b, 0, b.LengthReadComplete, fs);


    Console.WriteLine("현재 스레드 완료");
    Console.Read();
}

static void ReadComplete(IAsyncResult ar)
{
    FileStream fileStream = (FileStream)ar.AsyncState;
    fileStream.EndRead(ar);

    string s = Encoding.UTF8.GetString(b);

    Console.WriteLine(s);
}

 

예제에서 BeginRead 메서드를 보시면 작업이 완료되었을때 ReadComplete메서드를 호출하는 것을 확인할 수 있습니다. 이것은 다시 async / await 를 사용해 아래와 같이 바꿔볼 수 있습니다.

 

static byte[] b;
static void Main(string[] args)
{
    fileRead();

    Console.WriteLine("현재 스레드 완료");
    Console.Read();
}

static async void fileRead()
{
    FileStream fs = new FileStream("test.txt"FileMode.OpenFileAccess.ReadFileShare.Read);
    b = new byte[fs.Length];

    await fs.ReadAsync(b, 0, b.Length);

    string s = Encoding.UTF8.GetString(b);
    Console.WriteLine(s);
}

 

보시는 것처럼 완료후의 메서드로 따로 분리되지 않았습니다. 대신 ReadAsync메서드로 바뀌었는데 이 메서드는 특별히 await구문을 사용한 비동기 호출을 지원하기 위한 것이며 앞에 await 가 따로 지정되었습니다. 이렇게 하면 await가 사용된 구문 아래에 모든 처리는 해당 메서드처리가 모두 완료되고 나서야 처리가 진행됩니다.

 

fileRead메서드에는 async가 구문이 포함되어 있는데 이는 해당 메서드안에서 await가 사용될 것임을 알려주고 있습니다. async가 필요한 이유는 본래 await는 C# 5.0이후에 추가된 것으로 그 버전이전에 변수이름같이 await가 사용된 경우를 대비하기 위해서 입니다.

 

또한 C#에는 async / await 를 사용을 좀더 간단히 하기위해서 기존의 복잡한 비동기호출이 필요한 메서드 이외에 async / await 를 사용할 수 있는 메서드를 추가했습니다.

 

static void Main(string[] args)
{
    getWebData();

    Console.WriteLine("현재 스레드 완료");
    Console.Read();
}

static async void getWebData()
{
    HttpClient hc = new HttpClient();
    string s = await hc.GetStringAsync("http://www.naver.com/");

    Console.WriteLine(s);
}

 

위 예제는 HttpClient를 사용하여 특정 웹페이지의 데이터를 가져오는 구문인데 async / await 로 비동기호출을 시도했고 이에 대응하기 위해 await가 지원되는 GetStringAsync메서드를 호출하였습니다.

 

static void Main(string[] args)
{
    doWork();
    Console.WriteLine("현재 스레드 완료");
    Console.Read();
}

static async void doWork()
{
    Task<int> t1 = work5();
    Task<int> t2 = work10();

    await Task.WhenAll(t1, t2);

    Console.WriteLine("비동기 작업 완료");

    Console.WriteLine("결과 : {0}, {1}", t1.Result, t2.Result);
}

static Task<intwork5()
{
    return Task.Factory.StartNew(() => {
        Thread.Sleep(5000);
        Console.WriteLine("5초 작업 완료");
        return 3;
    });
}

static Task<intwork10()
{
    return Task.Factory.StartNew(() => {
        Thread.Sleep(10000);
        Console.WriteLine("10초 작업 완료");
        return 10;
    });
}

 

async / await 를 활용하면 위와 같이 특정 작업을 비동기로 병렬수행하는 것이 가능합니다. 이때 WhenAll은 Task타입을 반환하도록 되어 있어서 await 를 붙일 수 있는데 비슷한 처리를 하는 WaitAll 메서드는 작업이 완료될때까지 현재 스레드에서 대기해야 합니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET MVC] 영역(Area)  (0) 2018.10.10
[C#] 네트워크 - UDP  (0) 2018.09.20
[C#] async / await  (0) 2018.09.04
[C#] Path  (0) 2018.08.23
[ASP.NET MVC] 뷰 (View)  (0) 2018.08.14
[C#] using static  (0) 2018.07.27
0 0