[객체지향] 9.C#에서의 동시성 관리, C# 8.0 이상에서 소개된 Async Streams

1. 동시성이란 무엇인가?

동시성(Concurrency)은 여러 작업이나 실행 단위가 동시에 진행되는 능력을 의미한다. 이는 특히 I/O 작업이나 CPU 집약적인 작업을 효율적으로 처리하는 데 매우 중요하다. C#에서 동시성을 관리하는 방법은 여러 가지가 있으며, 그 중에서도 Async/Await 패턴과 Async Streams가 중요한 역할을 한다.

2. C#의 동시성 관리 방법

C#에서는 다양한 동시성 관리 기법을 제공한다. 가장 일반적으로 사용되는 기법으로는 스레드, 태스크(Task) 및 비동기 프로그래밍이 있다.

  • 스레드(Thread): C#에서는 System.Threading 네임스페이스를 통해 스레드를 생성하고 관리할 수 있다. 이는 메모리 소비가 크고 관리가 복잡하지만, 하드웨어 자원을 효율적으로 활용할 수 있다.
  • 태스크(Task): Task Parallel Library(TPL)는 스레드를 훨씬 쉽게 사용할 수 있도록 도와주는 API이다. 태스크는 비동기적으로 작업을 실행하는 보다 높은 수준의 추상화이다.
  • 비동기 프로그래밍(Async/Await): 이는 비동기 I/O 작업을 수행하기 위한 방법으로, 코드가 더 읽기 쉽고 유지보수하기 쉬운 장점이 있다. 비동기 메서드는 I/O 작업이 완료될 때까지 기다리지 않고 다른 작업을 수행할 수 있다.

3. C# 8.0의 Async Streams

C# 8.0에서 도입된 Async Streams는 비동기적으로 데이터를 스트리밍하는 기능을 제공한다. 이를 통해 데이터의 생성과 소비가 실시간으로 이루어질 수 있으며, 대규모 데이터 집합을 처리하는 데 유용하다.

Async Streams는 IAsyncEnumerable<T> 인터페이스를 기반으로 하며, await foreach 구문을 통해 데이터를 순차적으로 소비할 수 있다.

4. Async Streams 예제

다음 예제는 Async Streams를 사용하여 비동기적으로 숫자를 생성하고 이를 순차적으로 소비하는 코드이다.


                using System;
                using System.Collections.Generic;
                using System.Threading.Tasks;

                class Program
                {
                    static async IAsyncEnumerable<int> GenerateNumbersAsync(int count)
                    {
                        for (int i = 0; i < count; i++)
                        {
                            await Task.Delay(100); // 비동기 대기
                            yield return i; // 값 반환
                        }
                    }

                    static async Task Main(string[] args)
                    {
                        await foreach (var number in GenerateNumbersAsync(10))
                        {
                            Console.WriteLine(number);
                        }
                    }
                }
                

위 코드에서 GenerateNumbersAsync 메서드는 0부터 주어진 수까지의 숫자를 비동기적으로 생성한다. 각 숫자가 생성될 때마다 100ms의 대기 시간이 있다.

5. Async Streams의 장점

Async Streams를 사용하면 여러 가지 장점을 누릴 수 있다:

  • 메모리 사용 최적화: 데이터를 필요할 때만 로드하므로 메모리 소모가 적다.
  • 코드가 더 깔끔함: await foreach 구문을 사용하면 데이터 흐름을 쉽게 이해할 수 있다.
  • 비동기 I/O 최적화: 대량의 I/O 작업에서 성능을 극대화할 수 있다.

6. Async Streams 사용 시 유의 사항

Async Streams를 사용할 때는 몇 가지 주의해야 할 점이 있다:

  • 예외 처리: Async Stream에서 예외가 발생하면, 일반 스트림과 마찬가지로 await foreach 블록에서 처리해야 한다.
  • 완료 처리를 통한 자원 해제: 사용이 끝난 후에는 스트림을 닫아 자원을 해제해야 한다.

7. 결론

C# 8.0에서 도입된 Async Streams는 비동기적으로 데이터를 스트리밍하는 강력한 기능을 제공하여 개발자들이 복잡한 동시성 문제를 해결하는 데 도움을 준다. 이를 통해 비동기 작업의 성능을 향상시키고 메모리 사용을 최적화할 수 있다. Async/Await 개념과 결합하여 C#의 동시성 관리 기능은 더욱 강력해졌다.