본문 바로가기
programming | development/c#

Task , Parallel, async, await

by foooo828 2022. 1. 10.

병렬처리 비동기 처리 차이?

병렬은 작업을 여러개로 나눠 수행하고 하나의 결과로 만드는것

비동기는 각자 작업하고 각자 결과 받기

 

System.Threading.Task.Task

인스턴스 생성시 Action 대리자(반환형을 갖지 않는 메소드, 익명 메소드, 무명 함수 등)를 넘겨받음

    Action someAction = () => { Thread.Sleep(1000); };
    Task myTask = new Task(someAction);
    
    // 비동기 호출
    myTask.Start();
    // 비동기 포출이 완료될때 까지 기다림
    myTask.Wait();

Task.Run , Task<TResult>

           //Task 생성, 실행 한번에 하기
           Task.Run(() => { Console.WriteLine("어쩔티비"); });
            
           // 반환값있는 Task 쓰기
            var taskResult = Task<string>.Run(() =>
            {
              return "저쩔딤채";
            });
            Console.WriteLine(taskResult.Result);
            taskResult.Wait();
            Console.WriteLine("어쩔다이슨");

 

task.Result 프로퍼티가 비동기 작업이 끝나야 반환함

Task 클래스를 사용할때 Wait()를 항상 호출하는것이 좋음

 

Task<TResult> 를 활용한 병렬처리 예제

class Program
{
    static bool IsPrime(long number)
    {
        if (number < 2)
            return false;

        if (number % 2 == 0 && number != 2)
            return false;

        for (long i = 2; i < number; i++)
        {
            if (number % i == 0)
                return false;
        }

        return true;
    }

    static void Main(string[] args)
    {
        long from = 0;
        long to = 100000;
        int taskCount = 5;
        Func<object, List<long>> FindPrimeFunc =
            (objRange) =>
            {
                long[] range = (long[]) objRange;
                List<long> found = new List<long>();

                for (long i = range[0]; i < range[1]; i++)
                {
                    if (IsPrime(i))
                        found.Add(i);
                }

                return found;
            };

        Task<List<long>>[] tasks = new Task<List<long>>[taskCount];
        long currentFrom = from;
        long currentTo = to / tasks.Length;
        for (int i = 0; i < tasks.Length; i++)
        {
            Console.WriteLine("Task[{0}] : {1} ~ {2}",
                i, currentFrom, currentTo);

            tasks[i] = new Task<List<long>>(FindPrimeFunc,
                new long[] {currentFrom, currentTo});
            currentFrom = currentTo + 1;

            if (i == tasks.Length - 2)
                currentTo = to;
            else
                currentTo = currentTo + (to / tasks.Length);
        }

        Console.WriteLine("Please press enter to start...");
        Console.ReadLine();
        Console.WriteLine("Started...");

        DateTime startTime = DateTime.Now;

        foreach (Task<List<long>> task in tasks)
            task.Start();

        List<long> total = new List<long>();

        foreach (Task<List<long>> task in tasks)
        {
            task.Wait();
            total.AddRange(task.Result.ToArray());
        }

        DateTime endTime = DateTime.Now;

        TimeSpan ellapsed = endTime - startTime;

        Console.WriteLine("Prime number count between {0} and {1} : {2}",
            from, to, total.Count);
        Console.WriteLine("Ellapsed time : {0}", ellapsed);
    }
}

출력 값 : 

 

Task[0] : 0 ~ 20000
Task[1] : 20001 ~ 40000
Task[2] : 40001 ~ 60000
Task[3] : 60001 ~ 80000
Task[4] : 80001 ~ 100000
Please press enter to start...

Started...
Prime number count between 0 and 100000 : 9592
Ellapsed time : 00:00:00.5688669

 

 

Parallel

For(), Foreach()  메소드를 제공해 병렬처리를 더 쉽게 구현가능하게 해줌

For() 는 메소드를 병렬로 호출하여 몇개의 스레드를 사용할지 Parallel 클래스가 내부적으로 판단하여 최적화함

static void Main(string[] args)
{
    long from = 0;
    long to = 100000;

    Console.WriteLine("Please press enter to start...");
    Console.ReadLine();
    Console.WriteLine("Started...");

    DateTime startTime = DateTime.Now;
    List<long> total = new List<long>();

    Parallel.For(from, to, (long i) =>
    {
        if (IsPrime(i)) total.Add(i);
    });

    DateTime endTime = DateTime.Now;
    TimeSpan ellapsed = endTime - startTime;

    Console.WriteLine("Prime number count between {0} and {1} : {2}",
        from, to, total.Count);
    Console.WriteLine("Ellapsed time : {0}", ellapsed);
}

 

async 한정자 await 키워드

메소드 또는 이벤트 처리기를 선언할때 사용

사용시 비동기 코드를 만들 수 있음.

public static async Task AsyncMethod(){ ... }

async 사용시 반환형식은 void, Task, Task<TResult> 여야함.

- void 로 한정할 경우 await 없이도 완전한 비동기코드. 호출 즉시 호출자에게 제어를 돌려줌. 

- Task 나 Task<TResult>일경우 await 연산자를 만나는 곳에서 호출자에게 제어를 돌려줌. await 없으면 동기로 실행

 

 

참고: 

이것이 C# 이다

https://www.csharpstudy.com/

'programming | development > c#' 카테고리의 다른 글

Thread ,lock, Monitor  (0) 2022.01.09

댓글