2022. 2. 15. 00:00ㆍCSharp/Advance
TPL (Task Parallel Library)
다중 스레드 및 병렬 코드를 작성 하기 위한 .NET 권장 Library
애플리케이션에 병렬 처리 및 동시성 기능을 추가하는 과정을 단순화하여
개발자가 더 생산적으로 작업할 수 있도록 함
기본 사용법
Thread.CurrentThread.Name = "new Task";
Task taskA = new Task(() => Console.WriteLine("Hello from taskA."));
taskA.Start();
Console.WriteLine("Hello from thread '{0}'.",Thread.CurrentThread.Name);
taskA.Wait();
// output
// Hello from thread 'new Task'.
// Hello from taskA
Task.Run 을 통해 한 번에 작업을 만들고 시작할 수도 있다.
Thread.CurrentThread.Name = "Task.Run";
Task taskA = Task.Run(() => Console.WriteLine("Hello from taskA."));
Console.WriteLine("Hello from thread '{0}'.",Thread.CurrentThread.Name);
taskA.Wait();
// output
// Hello from thread 'Task.Run'.
// Hello from taskA
TaskFactory.StartNew 메서드를 사용하여 한 번에 작업을 만들고 시작할 수도 있다.
Thread.CurrentThread.Name = "Task.Factory.StartNew";
Task taskA = Task.Factory.StartNew(() => Console.WriteLine("Hello from taskA."));
Console.WriteLine("Hello from thread '{0}'.",Thread.CurrentThread.Name);
taskA.Wait();
// output
// Hello from thread 'Task.Factory.StartNew'.
// Hello from taskA.
Task 는 Return 값을 받을 수 있다.
private string HelloWorld() => "Hello World!";
public void TaskReturn()
{
Thread.CurrentThread.Name = "TaskReturn";
var taskA = Task.Factory.StartNew(() => HelloWorld());
Console.WriteLine("Hello from thread '{0}'.", Thread.CurrentThread.Name);
Console.WriteLine(taskA.Result);
// output
// Hello from thread 'TaskReturn'.
// Hello World!
}
lambda 식을 사용 할 때는 capture scope 을 신경쓰자
각 반복 후에 변경되는 값이 아니라 변수의 참조만 캡처한다.
Thread.CurrentThread.Name = "TaskCaptureScopeMistake";
Console.WriteLine("Hello from thread '{0}'.", Thread.CurrentThread.Name);
List<Task> tasks = new List<Task>();
for (int i = 0; i < 10; i++)
{
tasks.Add(Task.Factory.StartNew(() =>
{
Console.WriteLine($"i = [{i}]");
}));
}
// output
/*
Hello from thread 'TaskCaptureScopeMistake'.
i = [3]
i = [3]
i = [4]
i = [4]
i = [5]
i = [5]
i = [6]
i = [9]
i = [9]
i = [9]
*/
정확한 내용을 캡쳐 하려면 다음과 같이 한다.
Thread.CurrentThread.Name = "TaskCaptureScopeSolution";
Console.WriteLine("Hello from thread '{0}'.", Thread.CurrentThread.Name);
List<Task> tasks = new List<Task>();
for (int i = 0; i < 10; i++)
{
int j = i;
tasks.Add(Task.Factory.StartNew(() =>
{
Console.WriteLine($"i = [{j}]");
}));
}
Task.WaitAll(tasks.ToArray());
// output
/*
Hello from thread 'TaskCaptureScopeSolution'.
i = [0]
i = [2]
i = [1]
i = [6]
i = [5]
i = [4]
i = [3]
i = [7]
i = [9]
i = [8]
*/
연속작업 만들기
Task.ContinueWith 및 Task<TResult>.ContinueWith 메서드를 사용하면 선행 작업이 완료될 때 시작할 작업을 지정할 수 있다. 연속 작업의 대리자는 선행 작업에 대한 참조를 전달받아 선행 작업의 상태를 검사하고 Task<TResult>.Result 속성의 값을 검색하여 선행 작업의 출력을 입력으로 사용할 수 있다.
// 기본사용
Task task1 = Task.Factory.StartNew(() => Console.Write("Hello.."));
Task task2 = task1.ContinueWith(task => Console.Write("..world!"));
// output
// Hello....world!
// 이전 작업에서 throw 된 error 를 continuewith 와 함께 capture
Task task1 = Task.Factory.StartNew(() => throw new Exception("error fired"));
Task task2 = task1.ContinueWith(task => Console.Write("error capture" + task.Exception));
task2.Wait();
조건부 연속작업
기본적으로 연속 작업은 선행 작업이 완료되거나, 예외가 발생하거나, 취소되든 상관 없이 무조건 예약된다. TaskContinuationOptions 열거형에 포함된 (결합 가능한) 플래그 집합을 통해 이 동작을 변경할 수 있다.
Task t1 = Task.Factory.StartNew (...);
Task fault = t1.ContinueWith (ant => Console.WriteLine ("fault"),
TaskContinuationOptions.OnlyOnFaulted);
Task t3 = fault.ContinueWith (ant => Console.WriteLine ("t3"));
관련영상
'CSharp > Advance' 카테고리의 다른 글
Parallel Programming (PLINQ) (0) | 2022.02.17 |
---|---|
Parallel Programming (TPL Dataflow) (0) | 2022.02.16 |
Parallel Programming (Thread) (0) | 2022.02.14 |
범위와 인덱스 그리고 슬라이싱 (Range, Index and Slicing) (0) | 2022.02.11 |
LINQ Join Operators (조인연산자) (0) | 2022.02.10 |