[C#] Parallel 사용 방법 /예제/정의/추가적인작업

2023. 12. 26. 18:58·- 개발/C# 개발정리
반응형

Parallel : 단일 CPU를 사용했을 시절에는 CPU하나에 여러개의 Thread를 사용해서 처리했는데, 요즘에는 기본적으로 2~ 4개의 여러 CPU를 사용한다. 이러한

여러 CPU들을 골고루 사용하기 위해 .Net 4.0에서는 Parallel이라는 병렬 프로그래밍이 추가되었다.

 

1. Data Parallel : 각 CPU들에게 대량의 데이터를 병렬로 동시에 처리.

2. Task Parallel : 큰 작업을 Task로 분할해서 각 쓰레드들이 처리.

 

Parallel.Invoke() : 여러 작업들을 병렬로 처리, 다수의 작업 내용을 Action Delegate로 받아 다중 쓰레드들로 동시에 병렬 Task를 나눠서 실행.

 

※ TaskContinuationOptions

1. TaskContinuationOptions.None                    //선행작업이 어떤식으로 끝나든 이어서 실행하라는 옵션

2. TaskContinuationOptions.OnlyOnCanceled //선행작업이 취소가 되었을 때 이어서 실행하라는 옵션

3. TaskContinuationOptions.OnlyOnFaulted    //선행작업이 Fault가 되었을 때 이어서 실행하라는 옵션

4. TaskContinuationOptions.OnlyOnRanToCompletion //선행작업이 성공했을 때 이어서 실행하라는 옵션

 

[사용법]

----------------------------------------------------------------

// Loops : 루프의 범위를 지정하여 병렬로 처리할 수 있다.

public void Start1()
{
    var arr = Enumerable.Range(0, 10000);

    // 기존
    for (int i = 0; i < 100000; i++)
    DoWork(i);

    Thread.Sleep(5000);
    // TPL
    Parallel.For(0, 100000, (i) => DoWork(i));

    Parallel.Invoke(
    () => { DoWork1(); //임시 함수명 },
    () => { DoWork2(); //임시 함수명 }
    );

	Console.ReadLine();
}

 

[예제 1]

----------------------------------------------------------------

// 한 작업이 어떤 상태로 끝났을 때, 상태에 따른 추가적인 작업을 하게 만드는 소스

기본 예제 소스

void Factory()
{
	var displayData = Task.Factory.StartNew(() =>
	{
	}).ContinueWith((x) =>
	{
	}).ContinueWith((x) =>
	{
	});
}

----------------------------------------------------------------

public void Start5()
{
    Task<string> task = new Task<string>(Calc, 1L);

    task.Start();

    Task<string> justDoIt = task.ContinueWith<string>(
    (antecedentTask) =>
    {
    	Console.WriteLine("이전 작업 상태 : {0}", antecedentTask.Status);
    	return Calc(100001L);
	});
}

 

// 선행작업이 어떤식으로 끝나든 이어서 실행하라는 옵션

TaskContinuationOptions.None);

 

// 선행작업이 처리안된 예외를 던지는 상태에서만 이어서 실행하라는 옵션

//TaskContinuationOptions.OnlyOnFaulted

 

Task<string> justDoIt2 = justDoIt.ContinueWith<string>(
	(antecedentTask) =>
	{
		Console.WriteLine("이전 작업 상태 : {0}", antecedentTask.Status);
		return Calc(200001L);
	},
	TaskContinuationOptions.None);
	try
	{
		Console.WriteLine(task.Result);
	}
	catch (AggregateException ex)
	{
		foreach (var item in ex.InnerExceptions)
		{
			Console.WriteLine("에러 : {0}", item.Message);
		}
	}
	finally
	{
	try
	{
		Console.WriteLine(justDoIt.Result);
	}
	catch (AggregateException ex)
	{
		foreach (var item in ex.InnerExceptions)
		{
			Console.WriteLine("에러 : {0}", item.Message);
		}
	}
	finally
	{
        Console.WriteLine(justDoIt2.Result);
        Console.WriteLine("끝");
	}
	}
}

 

[Task 사용법]

public void Start2()
{
	const int max = 10000;
	
	//현재 작업중인 스레드외에 추가로 스레드를 생성
	Task task = new Task(() =>
	{
        for (int count = 0; count < max; count++)
        {
        	Console.Write("|");
        }
		Console.Write("추가 쓰레드 끝");
	});
	
	//추가 스레드 시작
	task.Start();
	
	//현재 작업중인 스레드에서도 반복문 시작
	for (int count = 0; count < max; count++)
	{
		Console.Write("-");
	}
	Console.Write("메인 쓰레드 끝");
	//혹시 현재 스레드가 빨리 끝나더라도,
	//추가 스레드가 끝날 때 까지 기다리기.
	task.Wait();
	
	//Wait메서드는 메인 스레드가 먼저 끝나더라도, 추가 스레드가 끝날 때까지 기다리게 하는 역할을 합니다. 그래서 메인 스레드가 빨리 끝나더라도, 항상 추가 스레드의 결과까지 제대로 출력되게 되는 것이죠.
    Console.ReadLine();
}

 

[예외 처리 사용법]

----------------------------------------------------------------

public void Start4()
{
	Task<string> task = new Task<string>(Calc, 1L);
	task.Start();
	try
    {
		Console.WriteLine(task.Result);
	}
	catch (AggregateException ex)
	{
		foreach (var item in ex.InnerExceptions)
		{
			Console.WriteLine("에러 : {0}", item.Message);
		}
    }
	Console.WriteLine(task.Result);
	Console.ReadLine();
}

----------------------------------------------------------------

 

[다른 Thread 종료 요청]

----------------------------------------------------------------

// 한 스레드에서 다른 스레드 종료 요청

 

// 한 스레드가 다른 스레드를 강제로 종료시키는 게 아니라,

작업 취소 API를 통해서 작업을 취소해줄 것을 요청하는 것이죠.

(Cancel Token 사용)

// 취소 플래그를 통해서 취소요청을 받은 작업은 취소요청에 어떻게 응답할 것인지 선택할 수 있습니다.

 

int cnt = 0;
public void PrintDash(CancellationToken cancellationToken)
{
    cancellationToken.Register(Canceled);
    //강제 에러호출
    if (cnt == 0)
        throw new ApplicationException("그냥 에러가 났음");

    while (!cancellationToken.IsCancellationRequested)
    {
        Console.Write("-");
    }
}
public void Canceled()
{
    Console.WriteLine("작업이 취소되었네.. (Cancel함수)");
}

public void Start6()
{
    string stars = "*".PadRight(Console.WindowWidth - 1, '*');

    CancellationTokenSource cancellationTokenSource =
    new CancellationTokenSource();

    Task task = Task.Factory.StartNew(
    () => PrintDash(cancellationTokenSource.Token),
    cancellationTokenSource.Token
    );
    //task가 에러 났을 때만 작업
    Task faultTask = task.ContinueWith(
    (x) =>
    {
        Console.WriteLine("에러남");
        cnt = 1; PrintDash(cancellationTokenSource.Token);
    },
    TaskContinuationOptions.OnlyOnFaulted
    );

    //task가 취소 됬을 때만 작업
    Task canceledTask = task.ContinueWith(
    (antecedentTask) => Console.WriteLine("취소됨"),
    TaskContinuationOptions.OnlyOnCanceled);
    Console.ReadLine();
    // cancellationTokenSource.Token = false : Cancel 함수 실행 전
    cancellationTokenSource.Cancel();
    Console.ReadLine();
    Console.WriteLine(stars);
    try
    {
        Console.WriteLine("작업의 완료상태 : {0}", task.Status);
        Console.WriteLine(faultTask.Status);
        Console.WriteLine(canceledTask.Status);
    }
    catch
    {

    }
    Console.WriteLine();
    Console.ReadLine();

}

 

 

[병렬 작업 & 병렬 처리 취소 방법]

----------------------------------------------------------------

public void Start7()
{
    int[] nums = Enumerable.Range(1, 10000000).ToArray<int>();

    //Task tt2 = Task.Factory.StartNew(() =>
    //{
    // Parallel.ForEach(nums, po2, (num) =>
    // Console.WriteLine(num * num));
    //});

    CancellationTokenSource cts = new CancellationTokenSource();

    ParallelOptions po = new ParallelOptions
    {
        CancellationToken = cts.Token
    };

    cts.Token.Register(
    () => Console.WriteLine("cts에 등록된 함수")
    );

    try
    {
        Task task = Task.Factory.StartNew(
        () =>
        {
            Parallel.For(0, 100, po,
    (i) => Console.WriteLine("Num : " + i));
        });

        Task task2 = task.ContinueWith(
        (x) =>
        {
            Console.WriteLine("정상처리");
        }, TaskContinuationOptions.OnlyOnRanToCompletion);
    }
    catch (OperationCanceledException ex)
    {
    }
    //Console.ReadLine();

    //cts.Cancel();

    Console.ReadLine();
}

 

 

[LINQ 활용]

----------------------------------------------------------------

public int[] SimpleParallelTask(int[] source, CancellationToken token)
{
    Func<int, int> square = (num) =>
    {
        Console.WriteLine(Task.CurrentId);
        return num * num * num * num * num * num * num * num * num * num * num * num * num * num
    * num * num * num * num * num * num * num * num * num * num;
    };

    return source.AsParallel()
    //병행으로 처리할 쓰레드 개수
    .WithDegreeOfParallelism(4)
    .WithCancellation(token)
    .Select(square)
    .ToArray();
}

 

 

반응형

'- 개발 > C# 개발정리' 카테고리의 다른 글

C# Boxing, UnBoxing, UpCasting, DownCasting 간단 설명 질문  (1) 2023.12.27
[C# Async/await/Invoke/beginInvoke/크로스스레딩] 비동기 처리 방법 /예제소스  (1) 2023.12.26
'- 개발/C# 개발정리' 카테고리의 다른 글
  • C# Boxing, UnBoxing, UpCasting, DownCasting 간단 설명 질문
  • [C# Async/await/Invoke/beginInvoke/크로스스레딩] 비동기 처리 방법 /예제소스
고미-
고미-
개발자의 블로그
    반응형
  • 고미-
    곰이네 Blog
    고미-
  • 전체
    오늘
    어제
    • 분류 전체보기 (51)
      • - 일상후기 (20)
        • IT (2)
        • 맛집 (9)
        • 애기들 (2)
      • - 개발 (8)
        • C# 개발정리 (3)
        • C# WPF (1)
        • Github (1)
        • Python (1)
      • - 자기개발 (1)
      • - 기타 (7)
  • 블로그 메뉴

    • 홈
    • > github
  • 링크

  • 공지사항

    • 바쁜 일상 속 잠깐 클릭해주세요!
  • 인기 글

  • 태그

    디저트
    커플
    모바일
    카페
    꽃
    삼국지책략전
    애기
    맛집
    귀여움
    프로그램
    삼국지
    선물
    고양
    이벤트
    말티즈
    내돈내산
    무료
    울산
    C#
    주차
    추천
    가성비
    카카오톡
    애드센스
    솔직후기
    생일
    블로그
    향동
    빵구독
    게임
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
고미-
[C#] Parallel 사용 방법 /예제/정의/추가적인작업
상단으로

티스토리툴바