본문 바로가기

공부중/CS 지식 한 줄

C# async/await 비동기 프로그래밍

C#에서 비동기 프로그래밍(asynchronous Programming)은 UI나 성능 최적화를 위해 중요한 개념이다. asyncawait 키워드를 사용하면 비동기 코드가 동기 코드처럼 자연스럽게 보이면서도 가독성을 높이고 성능을 향상시킬 수 있다.

 

1. 비동기 프로그래밍이란?

비동기 프로그래밍은 특정 작업(예: 네트워크 요청, 파일 읽기, 데이터베이스 작업 등)을 수행하는 동안 프로그래밍이 멈추지 않고 다른 작업을 수행할 수 있도록 하는 기법이다.

예를 들어, 사용자가 버튼을 눌렀을 때 API 호출을 한다고 가정한다면,

  • 동기 방식(Synchronous): API 요청이 끝날 때까지 UI가 멈춘다. (사용자가 아무것도 못 함)
  • 비동기 방식(Asynchronous): API 요청이 진행되는 동안 UI가 반응할 수 있다.

이런 동작을 위해 C#에서는 async와 await를 제공한다.

 

2. async와 await의 기본 개념

(1) async 키워드

  • async는 비동기 메서드를 정의할 때 사용한다.
  • 메서드의 반환 타입이 Task 또는 Task<T>가 되어야 한다.
  • async 메서드 내부에서 await 키워드를 사용할 수 있다.

(2) await 키워드

  • await는 비동기 작업이 끝날 때까지 기다렸다가 실행을 이어나가도록 해준다.
  • await를 사용하면 코드가 마치 동기식처럼 보이지만 실제로는 비동기 실행됨

3. 예제 코드와 실행 흐름

예제: HTTP 요청을 비동기적으로 실행하기

using System;
using System.Net.Http;
using System.Threading.Tasks;

class Program 
{
	static async Task Main()
    {
    	Console.WriteLine("요청 시작!");
        
    	string url = "https://jsonplaceholder.typicode.com/todos/1";
        string result = await FetchDataAsync(url);
        
        Console.WriteLine("응답 받은 데이터:");
        Console.WriteLine(result);
    }
    
    static aysnc Task<string> FetchDataAsync(string url)
    {
    	using (HttpClient client = new HttpClient()) // HTTP 클라이언트 생성
        {
        	Console.WriteLine("서버에 요청 보내는 중...");
            
        	HttpResponseMessage response = await client.GetAsync(url); // 비동기 호출
            
            Console.WriteLine("응답 받음!");
            
            return await response.Content.ReadAsStringAsync(); // 응답 내용을 문자열로 반환
        }
    }
}

 

실행 흐름

  • Main()에서 FetchDataAsync(url)를 호출(비동기 실행 시작)
  • FetchDataAsync()가 await client.GetAsync(url)을 만나면서 서버 응답을 기다리는 동안 다른 작업을 수행할 수 있음
  • 응답이 도착하면 await response.Content.ReadAsStringAsync()로 데이터를 읽음
  • 데이터를 Main()으로 반환한 후 출력

실행 결과 (예상)

요청 시작!
서버에 요청 보내는 중...
응답 받음!
응답 받은 데이터:
{
	"userId": 1,
    "id": 1,
    "title": "delectus aut autem",
    "completed": false
}

 

4. async와 await의 핵심 원리

(1) await를 만나면 C#은 어떻게 동작할까?

  • await는 현재 작업을 멈추고, 나머지 코드 실행을 나중으로 미룸
  • 대신 CPU는 다른 작업을 수행할 수 있도록 대기 상태로 둠
  • 작업이 완료되면 await 뒤의 코드가 실행됨

(2) Task와 Task<T>

비동기 메서드는 Task 또는 Task<T>를 반환해야 한다.

  • Task: 단순한 비동기 작업(void와 비슷함)
  • Task<T>: 결과값을 반환하는 비동기 작업

예제

async Task DoSomethingAsync() // Task만 반환 (결과 없음)
{
	await Task.Delay(1000); // 1초 대기
    Console.WriteLine("작업 완료!");
}

async Task<int> GetNumberAsync() // Task<int> 반환 (결과 있음)
{
	await Task.Delay(500);
    return 42;
}

 

5. await 없이 async만 사용하면?

async Task<int> GetNumberAsync()
{
	return 100; // 바로 값을 반환
}
  • await를 사용하지 않으면 비동기 실행이 아니라 즉시 반환됨
  • 즉, 비동기 코드에서 await를 안 쓰면 의미가 없을 수도 있음

예를 들어, 아래처럼 await 없이 호출하면 Task<int> 객체가 반환될 뿐, 실제 값을 기다리지 않음

Task<int> task = GetNumberAsync();
Console.WriteLine(task.Result); // 동기적으로 결과를 가져옴
  • task.Result를 사용하면 비동기 작업이 끝날 때까지 기다리지만, 프로그램이 멈출 위험이 있음
  • 따라서 가능하면 await를 사용하여 처리하는 것이 좋다.

6. async와 await를 사용할 때 주의할 점

(1) async void를 피하자

비동기 메서드는 Task나 Task<T>를 반환해야 한다.

async void BadAsyncMethod()
{
	await Task.Delay(1000);
}
  • async void는 예외 처리가 어렵고, 호출한 코드가 완료를 추적할 수 없음
  • 대신 async Task를 사용하자

(2) ConfigureAwait(false) 활용

UI 스레드가 없는 환경(예: 백엔드 서버)에서는 await someTask.ConfigureAwait(false)를 사용하면 성능이 향상될 수 있다.

 

7. 요약

개념 설명
async 비동기 메서드 정의
await 비동기 작업을 기다림
Task 비동기 실행을 나타내는 객체
Task<T> 결과를 반환하는 비동기 작업
async void 피해야 함 (예외 처리 어려움)

 

8. 정리

  • async와 await를 사용하면 비동기 코드를 동기 코드처럼 자연스럽게 작성 가능
  • await는 비동기 작업이 끝날 때가지 기다렸다가 다음 코드 실행
  • Task와 Task<T>를 활용하여 비동기 작업을 관리할 수 있음
  • UI 어플리케이션에서는 async를 활용하여 UI 멈춤 현상을 방지할 수 있음

'공부중 > CS 지식 한 줄' 카테고리의 다른 글

DNS(Domian Name System)  (0) 2025.03.10
C# var, dynamic, object 차이점  (0) 2025.03.10
트랜잭션(Transaction) ACID 원칙  (0) 2025.03.07