프로그래밍/C#

비동기 프로그래밍과 C#의 Task Parallel Library (TPL) 활용법

shimdh 2025. 9. 4. 10:04
728x90

비동기 프로그래밍은 현대 소프트웨어 개발에서 필수적인 기술로 자리 잡았습니다. 특히 C#의 Task Parallel Library (TPL)는 비동기 작업을 효율적으로 처리할 수 있는 강력한 도구를 제공합니다. 이번 블로그 포스트에서는 비동기 프로그래밍의 개념과 TPL을 활용한 다양한 기법을 살펴보겠습니다.

비동기 프로그래밍 이해하기

동시성 vs. 병렬성

  • 동시성: 여러 작업을 동시에 처리하는 것을 의미하지만, 반드시 동시에 실행되는 것은 아닙니다.
  • 병렬성: 여러 작업을 동시에 실행하는 것을 포함하며, 멀티코어 프로세서를 활용하여 성능을 향상시킵니다.

비동기 프로그래밍을 사용하는 이유

  1. 애플리케이션 응답성 향상: 백그라운드 작업이 실행되는 동안 사용자는 애플리케이션과 계속 상호작용할 수 있습니다.
  2. 자원 활용도 개선: 파일 접근이나 네트워크 요청과 같은 I/O 바운드 작업을 수행할 때 스레드와 시스템 자원을 효율적으로 관리합니다.

핵심 개념

  • 태스크: 메인 프로그램 흐름과 독립적으로 실행될 수 있는 비동기 작업을 나타냅니다.
  • asyncawait 키워드: 비동기 코드를 보다 동기적인 스타일로 작성할 수 있게 하여 비차단 동작의 이점을 유지하면서도 코드를 간소화합니다.
728x90

Task Parallel Library (TPL) 개요

TPL은 .NET Framework 4에 도입되었으며, 병렬 프로그래밍을 위한 API 세트를 제공하여 멀티코어 환경에서 확장 가능한 애플리케이션을 쉽게 구축할 수 있도록 합니다.

태스크 생성하기

Task myTask = Task.Run(() => {
    // 작업 시뮬레이션
    Thread.Sleep(2000);
    Console.WriteLine("태스크 완료!");
});

myTask.Wait(); // 필요시 완료 대기

결과 처리하기

Task<int> calculateSum = Task.Run(() => {
    int sum = 0;
    for (int i = 1; i <= 100; i++) {
        sum += i;
    }
    return sum;
});

int result = await calculateSum; // 대기를 통해 직접 결과 얻기
Console.WriteLine($"합계는 {result}입니다");

예외 처리

try {
    await Task.Run(() => { throw new InvalidOperationException("오류!"); });
} catch (InvalidOperationException ex) {
    Console.WriteLine(ex.Message); // 여기서 예외 처리
}

병렬 ForEach 루프

var numbers = Enumerable.Range(1, 100);

Parallel.ForEach(numbers, number => {
    Console.WriteLine($"숫자 처리 중: {number}");
    Thread.Sleep(50); // 작업 시뮬레이션
});

취소 토큰

CancellationTokenSource cts = new CancellationTokenSource();
var token = cts.Token;

Task longRunningTask = Task.Run(() =>
{
    while (!token.IsCancellationRequested)
    {
        // 작업 수행...
        Thread.Sleep(100);
        Console.WriteLine("작업 중...");

        if (/* 특정 조건 */)
            cts.Cancel(); // 논리에 따라 취소 요청.

      }
}, token);

try 
{
      await longRunningTask;
}
catch(TaskCanceledException) 
{
      Console.WriteLine("태스크가 취소되었습니다.");
}

TPL과 함께 Async/Await 사용하기

public async Task<string> FetchDataAsync(string url)
{
     using(HttpClient client = new HttpClient())
     {
          string data = await client.GetStringAsync(url); 
          return data;  
     }
}

// 비동기 컨텍스트 내 사용 예시.
string responseData = await FetchDataAsync("https://api.example.com/data");
Console.WriteLine(responseData);

결론

TPL을 사용한 비동기 프로그래밍은 개발자들이 응답성과 고성능을 갖춘 애플리케이션을 만들 수 있도록 하며, 동시 작업을 효율적으로 관리하고 시스템 자원을 효과적으로 활용할 수 있게 합니다. 태스크 생성, 결과 및 예외 처리, 병렬 루프 구현, 취소 관리, 그리고 async/await 패턴을 워크플로에 통합하는 등의 핵심 개념을 이해함으로써 개발자들은 애플리케이션의 성능 특성을 더 잘 제어할 수 있으며, 코드베이스의 가독성을 유지할 수 있습니다.

728x90