REST API 서버로부터 데이터을 비동기 방식으로 응답받아 화면 출력을 할때 메서드를 구현하면서 async, await, Task 등을 많이 사용했는데 일단 구현은 했어도 이해가 안되는 부분이 많았어서 정리
async는 비동기 메서드를 정의할 때 사용됩니다. 메서드에 async 키워드를 붙이면, 그 메서드는 비동기 방식으로 실행될 수 있습니다.
public async Task MyAsyncMethod()
{
// 비동기 작업을 수행할 수 있는 메서드
}
await는 비동기 작업의 완료를 기다리는 역할을 합니다. await가 붙은 작업이 완료될 때까지 기다리지만, 중요한 점은 이 대기 동안 다른 작업들을 할 수 있도록 메인 쓰레드를 블로킹(blocking)하지 않는다는 것입니다.
HttpResponseMessage response = await client.GetAsync("http://example.com");
위 코드에서 await는 client.GetAsync() 메서드의 완료를 기다리면서 다른 작업을 할 수 있게 합니다.
Task는 비동기 작업을 표현하는 객체입니다. 비동기 메서드에서 어떤 작업을 수행하고 그 결과를 반환할 때 사용합니다.
비동기 작업이 완료될 때까지의 약속(Promise)을 나타낸다고 생각할 수 있습니다.
비동기 메서드에서 반환 값이 없다면 Task를, 반환 값이 있다면 Task<T>를 사용합니다. 예를 들어, Task<int>는 비동기 메서드가 정수(int) 값을 반환할 것이라는 의미입니다.
private async Task LoadBoardList()
{
HttpResponseMessage response = await client.GetAsync("http://example.com/api/boards");
if (response.IsSuccessStatusCode)
{
string result = await response.Content.ReadAsStringAsync();
var boards = JsonConvert.DeserializeObject<List<BoardDto>>(result);
dataGridViewBoard.DataSource = boards;
}
else
{
MessageBox.Show("게시글 목록을 불러오는 데 실패했습니다.");
}
}
await client.GetAsync(...) : 서버에 요청을 보낸 뒤 응답 대기. 이 동안 다른 작업 수행할 수 있으며, 응답이 올 때까지 프로그랩은 멈추지 않습니다.이렇게 async, await, Task를 사용하면 비동기 작업을 할 때 프로그램이 멈추치 않고 자연스럽게 동작하게 되어 사용자 경험이 좋아지고, 성능이 개선되는 효과를 볼 수 있습니다.
즉, 비동기 메서드에 async를 붙이는 것은 해당 메서드를 비동기로 실행할 수 있다는 의미입니다. void, Task, Task<T>를 선택하는 것은 메서드가 반환하는 정보가 무엇인지를 나타냅니다.
예를 들어 LoadBoardList()메서드를 async Task로 구현하여 버튼을 클릭시 게시글 목록을 조회하는 기능을 구현한다면
private async Task LoadBoardList()
{
HttpResponseMessage response = await client.GetAsync("http://example.com/api/boards");
if (response.IsSuccessStatusCode)
{
string result = await response.Content.ReadAsStringAsync();
var boards = JsonConvert.DeserializeObject<List<BoardDto>>(result);
dataGridViewBoard.DataSource = boards;
}
else
{
MessageBox.Show("게시글 목록을 불러오는 데 실패했습니다.");
}
}
private async void btnSearch_Click(object sender, EventArgs e)
{
await LoadBoardList();
}
LoadBoardList()메서드는 반환타입이 Task입니다. Task를 반환하는 이유는 호출자에게 이 메서드가 비동기 작업을 진행하고 있고, 완료될 때까지 기다릴 수 있다는 약속을 제공하기 위해서입니다.
LoadBoardList() 메서드를 호출하는 쪽에서는 이 메서드가 완료되기를 기다려야 할 수 있습니다. 이때 Task를 반환하면 호출자는 await를 사용하여 해당 메서드가 끝날 때까지 대기할 수 있습니다.
btnSearch_Click 이벤트 핸들러가 LoadBoardList()를 호출할 때 await을 사용할 수 있는 이유는 LoadBoardList()가 Task를 반환하기 때문입니다.LoadBoardList()가 void를 반환한다면, 호출자는 해당 작업이 끝났는지 여부를 알 방법이 없으며 await으로 기다릴 수 없습니다.btnSearch_Click과 같은 이벤트 핸들러에서 주로 사용됩니다. 이벤트 핸들러는 일반적으로 반환 값을 필요로 하지 않으며, 이벤트가 발생할 때마다 실행되기 때문에 void로 선언해도 사용하는데 문제가 없습니다.void: 이벤트 핸들러처럼 반환 값을 필요로 하지 않는 경우 사용Task: 호출자가 비동기 작업의 완료를 기다려야 하는 경우 사용Task<T>: 비동기 작업이 완료된 후 값을 반환해야 할 때 사용일반적인 비동기 메서드에서는 void 대신 Task사용이 권장됩니다. Task를 반환하지 않고 void로 처리할 경우, 예외 처리가 더 어려워질 수 있고 호출자가 작업의 완료를 알 수 있는 방법이 없기 때문에 비동기 작업에 대한 흐름 관리가 불가능해질 수 있습니다.