카테고리 없음

비동기 프로그래밍에 대해 알아보자. #2 (Task)

근본넘치는개발자 2024. 11. 14. 20:49

 

2024.11.12 - [분류 전체보기] - 비동기 프로그래밍에 대해 알아보자. #1 ( Await 과 async)

2024.11.13 - [분류 전체보기] - 스레드(Thread)와 스레드 풀(ThreadPool)에 대해 알아보자

 

지난 시간에 이어  

오늘은 비동기 프로그래밍 Task에 대해서 정리해 보고자 합니다.

Task

Thread와 ThreadPool의 단점을 개선한 비동기 프로그래밍 

 

내부적으로 스레드 풀을 이용하여 작업을 처리

백그라운드 스레드로 동작 / 스레드 풀 스레드를 사용하여 작업 실행

 

Task의 주요 메서드

 

Start():

Task를 시작하는 메서드

 

Wait():

특정 Task가 완료될 때까지 현재 스레드를 대기시키는 메서드

 

ContinueWith():

Task가 완료된 후 수행할 작업을 지정하는 메서드

 

Run():

Task를 즉시 실행하는 간편한 메서드

 

WaitAll():

여러 Task가 모두 완료될 때까지 대기하는 메서드

 

Task 사용의 장점

작업 완료 후 연속 작업(ContinueWith) 지원

여러 작업의 동시 실행 및 완료 대기 기능 제공

람다식을 통한 간편한 작업 정의 가능

비동기 프로그래밍에 최적화된 구조

 

예시 

더보기
using System;
using System.Threading;
using System.Threading.Tasks;

class TaskExamples
{
    // 1. 기본적인 Task 생성 및 실행
    public async Task BasicTaskExample()
    {
        // Task.Run을 사용한 간단한 작업 실행
        Task simpleTask = Task.Run(() =>
        {
            Console.WriteLine("기본 Task 실행 중...");
            Thread.Sleep(1000);
            Console.WriteLine("기본 Task 완료!");
        });

        await simpleTask; // Task 완료 대기
    }

    // 2. 반환값이 있는 Task
    public async Task<int> TaskWithReturnValue()
    {
        Task<int> calculateTask = Task.Run(() =>
        {
            Console.WriteLine("계산 작업 시작...");
            Thread.Sleep(2000); // 복잡한 계산 시뮬레이션
            return 42;
        });

        int result = await calculateTask;
        Console.WriteLine($"계산 결과: {result}");
        return result;
    }

    // 3. 여러 Task 동시 실행
    public async Task MultipleTasksExample()
    {
        Task task1 = Task.Run(() =>
        {
            Thread.Sleep(2000);
            Console.WriteLine("Task 1 완료");
        });

        Task task2 = Task.Run(() =>
        {
            Thread.Sleep(1000);
            Console.WriteLine("Task 2 완료");
        });

        Task task3 = Task.Run(() =>
        {
            Thread.Sleep(3000);
            Console.WriteLine("Task 3 완료");
        });

        await Task.WhenAll(task1, task2, task3);
        Console.WriteLine("모든 Task 완료!");
    }

    // 4. ContinueWith 사용 예시
    public void ContinueWithExample()
    {
        Task.Run(() =>
        {
            Console.WriteLine("첫 번째 작업 실행");
            Thread.Sleep(1000);
            return "첫 번째 작업 결과";
        })
        .ContinueWith(previousTask =>
        {
            Console.WriteLine($"이전 작업 결과: {previousTask.Result}");
            Console.WriteLine("두 번째 작업 실행");
        });
    }

    // 5. 실제 활용 예시 - 파일 처리 시뮬레이션
    public async Task ProcessFilesSimulation()
    {
        // 파일 처리 작업 시뮬레이션
        Task<string[]> readTask = Task.Run(() =>
        {
            Console.WriteLine("파일 읽기 시작...");
            Thread.Sleep(2000); // 파일 읽기 시뮬레이션
            return new string[] { "데이터1", "데이터2", "데이터3" };
        });

        // 데이터 처리 작업
        Task<string[]> processTask = readTask.ContinueWith(t =>
        {
            string[] data = t.Result;
            Console.WriteLine("데이터 처리 중...");
            Thread.Sleep(1000);
            return data.Select(d => d.ToUpper()).ToArray();
        });

        // 결과 저장 작업
        Task saveTask = processTask.ContinueWith(t =>
        {
            string[] processedData = t.Result;
            Console.WriteLine("결과 저장 중...");
            Thread.Sleep(1000);
            Console.WriteLine("모든 처리 완료!");
        });

        await saveTask;
    }

    // 6. 취소 토큰 사용 예시
    public async Task CancellationExample()
    {
        using (var cts = new CancellationTokenSource())
        {
            try
            {
                Task longRunningTask = Task.Run(() =>
                {
                    for (int i = 0; i < 10; i++)
                    {
                        cts.Token.ThrowIfCancellationRequested();
                        Console.WriteLine($"작업 진행 중... {i * 10}%");
                        Thread.Sleep(500);
                    }
                }, cts.Token);

                // 3초 후 작업 취소
                await Task.Delay(3000);
                cts.Cancel();
                await longRunningTask;
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine("작업이 취소되었습니다.");
            }
        }
    }

    // 메인 실행 메서드
    public async Task RunAllExamples()
    {
        Console.WriteLine("=== Task 예제 실행 시작 ===");
        
        await BasicTaskExample();
        Console.WriteLine("\n-------------------\n");
        
        await TaskWithReturnValue();
        Console.WriteLine("\n-------------------\n");
        
        await MultipleTasksExample();
        Console.WriteLine("\n-------------------\n");
        
        ContinueWithExample();
        Console.WriteLine("\n-------------------\n");
        
        await ProcessFilesSimulation();
        Console.WriteLine("\n-------------------\n");
        
        await CancellationExample();
        
        Console.WriteLine("=== 모든 예제 실행 완료 ===");
    }
}

 

 

마무리 

오늘은 간단하게 Task에 대해 정리해 봤습니다.

Task까지 이해하셨다면 이제 Await과 async를 다시 한번 읽어보시면 됩니다! 

 

다음 시간에는 UniTask, Awaitable을 정리해보겠습니다.

 

2024.11.18 - [분류 전체보기] - 유니티 - 비동기 프로그래밍에 대해 알아보자. #3 (UniTask)

 

참고한 자료 

https://youtu.be/Zp1-Y_z7t10?si=IOoNK9_jdzUy1xqo