프로그래밍/(도서)C#코딩의기술-실전

[C#] 코딩의기술(실전편) - 1.4 병렬처리

Victory_HA 2022. 3. 31. 22:24

동기 처리, 비동기 처리, 병렬 처리

  • 한개 프로세스 안에서 동시에 여러 개의 일을 하려면 다중 쓰레드(Thread)가 필요합니다.
  • 동시에 여러 개의 일을 한다는 측면에서 비동기와 병렬처리는 맥락을 같이합니다.
  • 동기 처리 : 책을 읽듯이 순차적으로 처리하는 것 입니다.
    • User의 입력이 필요한 경우, User 입력을 받기 전까지는 다음 줄로 넘어가 실행할 수 없는 상태로 컴퓨터는 멈춰있을것이다.
  • 비동기 처리 : 실행되는 타이밍을 다 맞추는 것이 아니라 User 입력을 받는 부분은 별도로 처리한다.
  • 병렬처리 : 병렬 처리란 여러 개의 프로세서를 통해 하나의 프로그램을 처리하는 것을 말합니다.
    • 처리 부하를 분담하여 처리 속도의 향상시킵니다.
  • 참고

병렬 처리를 위한 클래스 라이브러리 TPL (Taks Parallel Library)

  • System.Threading 및 System.Threading.Tasks 네임스페이스에 포함된 공용 형식 및 API의 집합입니다.
  • 병렬 처리 및 동시성 기능을 추가하는 과정을 단순화 하도록 합니다.
  • System.Threading.Tasks.Parallel 클래스를 통해 데이터 병렬 처리를 지원합니다.
    • Parallel.For(), Parallel.Foreach() 메서드로 병렬 처리를 구현합니다.
    • 스레드나 큐 작업 항목을 만들 필요가 없습니다.
    • 기본 루프에서는 잠금을 수행할 필요가 없습니다.

Parallel.For() 사용예제

class Program
{
    private const int NumberOfRetries = 3;
    private const int DelayOnRetry = 1000;

    static void Main(string[] args)
    {
        // 1. 순차 처리
        // 한개의쓰레드가 0~999 출력
        for (int i = 0; i < 1000; i++)
        {
            Console.WriteLine("Current Thread ID : {0}, Count : {1}",
                Thread.CurrentThread.ManagedThreadId, i);
        }
        Console.Read();

        // 2. 병렬 처리
        // 다중쓰레드가 병렬로 출력
        Parallel.For(0, 1000, (i) => {
            Console.WriteLine("Current Thread ID : {0}, Count : {1}",
                Thread.CurrentThread.ManagedThreadId, i);
        });

        Console.Read();
    }
}

실행결과 - 1. 순차 처리

실행결과 - 2. 병렬 처리

Task의 종료 확인

  • Task는 값을 반환하지 않고 일반적으로 비동기식으로 실행되는 단일 작업을 나타냅니다.
  • 경우에 따라, Task1의 결과 값을 Task2에서 활용해야하는 경우 Task1의 작업 종료까지 기다려야 할 수 있습니다.

Task의 종료 확인 방법1

  • Task.IsCompleted
    • Task 하나의 종료를 확인합니다.
  • Task.WaitAll()
    • Parameter로 입력되는 모든 Task가 끝날 때까지 대기합니다.
  • Task.WaitAny()
    • Parameter로 입력되는 Task중 한개가 끝나면 대기를 종료합니다.

사용 예제

private static void work(int n, int wait)
{
    Console.WriteLine($"Task{n} : {DateTime.Now.ToString("HH:mm:ss")}");
    Task.Delay(1000 * wait).Wait();
    Console.WriteLine($"Task{n} [ElapsedTime]: {DateTime.Now.ToString("HH:mm:ss")}");
}
static void Main(string[] args)
{
    var t1 = Task.Run(() => { work(1, 2); });
    var t2 = Task.Run(() => { work(2, 3); });
    var t3 = Task.Run(() => { work(3, 5); });
    var t4 = Task.Run(() => { work(4, 1); });

    //// t1 Task가 종료
    if (t1.IsCompleted)
    {
        Console.WriteLine("t1 is done.");
    }

    //// 모든 Task가 종료
    //Task.WaitAll(t1, t2, t3, t4);
    //Console.WriteLine("All done.");

    //// Task 중 하나가 종료
    //Task.WaitAny(t1, t2, t3, t4);
    //Console.WriteLine("Something is done.");
}

Task의 종료 확인 방법2

  • Parallel.Invoke() 메서드
    • 파라미터로 입력되는 작업을 병렬로 실행합니다.
    • 모든 Task가 끝날 때까지 대기합니다.

사용예제

static void Main(string[] args)
{
    Parallel.Invoke(
        () => { work(1, 2); },
        () => { work(2, 3); },
        () => { work(3, 5); },
        () => { work(4, 1); }
        );
    Console.WriteLine("All done.");
}

참조