안녕하세요. 명월입니다.
이 글에서는 async와 await를 소개하겠습니다.
async와 await은 Task 클래스와 매우 밀접한 관계가 있으므로 먼저 Task 클래스의 글을 함께 보면 이해하기 쉽습니다.
링크 - [C# 강좌 - 54]Task 클래스
먼저 async 키워드는 void로 사용하는 방법과 Task클래스와 사용하는 방법이 두가지로 나누어져 있습니다.
먼저 void로 사용하는 방법입니다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace Example
{
class Program
{
// 단독으로 사용할 때는 void를 사용한다.
static async void AsyncTest()
{
var task = new Task<int>(() =>
{
int sum = 0;
for (int i = 0; i < 10; i++)
{
sum += i;
// 0.1초 단위로 1씩 증감
Console.WriteLine(i);
Thread.Sleep(100);
}
return sum;
});
task.Start();
}
static void Main(string[] args)
{
// Task 리턴식이 없기 때문에 제어할 수가 없다.
AsyncTest();
Console.WriteLine("Press Any Key...");
Console.ReadKey();
}
}
}
위 소스를 보면 async 메서드에 task를 넣고 실행했습니다. 사실 async - void는 그냥 비동기입니다. ThreadPool로 만드는 것과 차이가 없습니다.
별 의미도 없고 그냥 위처럼 만든다면 그냥 async없이 Task 클래스만 사용하는 게 맞습니다. 실제 저렇게 코딩하면 Visual studio에서도 warning 메시지 나옵니다.
warning 메시지 뜻은 조금 다른 내용인데 비슷한 말입니다.
그러므로 async 키워드는 리턴 값이 Task으로 사용하는게 맞는 것 같습니다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace Example
{
class Program
{
// 단독으로 사용할 때는 void를 사용한다.
static async Task<int> AsyncTest()
{
var task = new Task<int>(() =>
{
int sum = 0;
for (int i = 0; i < 10; i++)
{
sum += i;
// 0.1초 단위로 1씩 증감
//Console.WriteLine(i);
Thread.Sleep(100);
}
return sum;
});
task.Start();
//외부에서 await에서 기다린다.
await task;
// Wait가 호출되면 통과된다.
Console.WriteLine(task.Result);
return 10;
}
static void Main(string[] args)
{
var task = AsyncTest();
Console.WriteLine("pass await 1");
// Wait
task.Wait();
Console.WriteLine("pass await 2");
//결국 Return까지 기다린다.
int result = task.Result;
//결과 같은 10이다.
Console.WriteLine(result);
Console.WriteLine("Press Any Key...");
Console.ReadKey();
}
}
}
우리가 쓰레드를 만들 때 실제 호출하는 쪽에서 쓰레드 안의 제어를 하기 쉽지 않습니다. 문제는 동기화 때문입니다.
그러나 async - await을 쓰면 제어가 가능해 집니다.
위 예제는 Main에서 AsyncTest를 호출했습니다. AsyncTest 메서드 안에서는 task가 실행됩니다. 물론 비동기로 실행됩니다. 여기서 이 쓰레드를 잠깐 멈추게 하고 싶습니다. 그럼 외부에서 Wait함수를 부르면 되는데 이 때 await 키워드로 멈추는 포인트를 지정할 수 있는 것입니다.
이렇게 되면 순서는 결과의 순서는 「pass await 1」 => 「45」 => 「pass await 2」 => 「10」 으로 출력이 됩니다.
다음은 async와 더불어 많이 사용하는 ContinueWith 함수를 소개하겠습니다.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace Example
{
class Program
{
static async Task<int> AsyncTest()
{
var task = new Task<int>(() =>
{
int sum = 0;
for (int i = 0; i < 10; i++)
{
sum += i;
// 0.1초 단위로 1씩 증감
Console.WriteLine(i);
Thread.Sleep(100);
}
return sum;
});
task.Start();
await task;
task = new Task<int>(() =>
{
int sum = 0;
for (int i = 10; i < 20; i++)
{
sum += i;
Thread.Sleep(100);
}
return sum;
});
task.Start();
// await이 위에 있지만 결국에는 145가 리턴된다.
return task.Result;
}
static void Main(string[] args)
{
//AsyncTest 끝나면 이어서 실행된다. 즉, AsyncTest가 종료되면 실행되는 Thread
var continueTask = AsyncTest().ContinueWith(task =>
{
return task.Result;
});
//continueTask 끝날때까지 기다린다.
Console.WriteLine(continueTask.Result);
Console.WriteLine("Press Any Key...");
Console.ReadKey();
}
}
}
ContinueWith 함수는 Task를 연달아 붙여서 사용할 때 사용합니다. 이 뜻은 Task => Wait => Result => Task => Wait => Result 이지만 위처럼 ContinueWith함수를 써서 간단하게 처리를 했습니다.
ContinueWith는 C#의 콜백 함수라고도 부르는 사람도 있습니다.
여기까지 async와 await 설명이었습니다.
궁금한 점이나 잘못된 점이 있으면 댓글 부탁드립니다.
'Study > C#' 카테고리의 다른 글
[C# 강좌 - 70] Entity Framework 설정하기 (0) | 2019.07.03 |
---|---|
[C# 강좌 - 69] MVC Framework에서 Controller에서 View 설정하기 (0) | 2019.07.02 |
[C# 강좌 - 68] MVC Framework filter 설정하기 (0) | 2019.07.02 |
[C# 강좌 - 67] MVC Framework 프로젝트 생성하기 (0) | 2019.07.01 |
[C# 강좌 - 43] WIndow Form - 5 Graphic (0) | 2012.10.17 |
[C# 강좌 - 42] WIndow Form - 4 구조체 , 모달과 모달리스 (0) | 2012.10.16 |
[C# 강좌 - 40] WIndow Form - 2 SDI, MDI (0) | 2012.10.14 |
[C# 강좌 - 38] ADO 데이터 베이스 - 3 (0) | 2012.10.12 |