https://www.oreilly.com/library/view/concurrency-in-c/9781492054498/
Concurrency in C# Cookbook, 2nd Edition
If you’re one of many developers still uncertain about concurrent and multithreaded development, this practical cookbook will change your mind. With more than 85 code-rich recipes in this updated second … - Selection from Concurrency in C# Cookbook, 2n
www.oreilly.com
데이터 병렬
void RotateMatrices(IEnumerable<Matrix> matrices, float degrees)
{
Parallel.ForEach(matrices, matrix => matrix.Rotate(degrees));
}
IEnumerable<bool> PrimalityTest(IEnumerable<int> values)
{
return values.AsParallel()
.Select(value => IsPrime(value));
}
작업 병렬(병렬 호출)
void ProcessArray(double[] array)
{
Parallel.Invoke(
() => ProcessPartialArray(array, 0, array.Length / 2),
() => ProcessPartialArray(array, array.Length / 2, array.Length)
);
}
void ProcessPartialArray(double[] array, int begin, int end)
{
// CPU 집약적인 처리
}
작업 병렬에서는 특히 closure 안에 캡처한 변수에 주의해야 한다.
값이 아닌 참조를 캡처하므로 명확하지 않은 공유가 일어날 수도 있다.
try
{
Parallel.Invoke(
() => { throw new Exception(); },
() => { throw new Exception(); });
}
catch (AggregateException ex)
{
ex.Handle(exception =>
{
Trace.WriteLine(exception);
return true; // 처리함
});
}
루푸 중지
void InvertMatrices(IEnumerable<Matrix> matrices)
{
Pallel.ForEach(matrices, (matrix, state) =>
{
if (matrix.InInvertible)
matrix.Invert();
else
state.Stop();
});
}
중지는 루프의 내부에서 일어나며 취소는 루푸의 외부에서 일어난다.
void RotateMatrices(IEnumerable<Matrix> matrices, float degrees, CancellationToken token)
{
Parallel.ForEach(matrices,
new ParallelOptions { CancellationToken = token },
matrix => matrix.Rotate(degrees));
}
공유 상태를 보호하는 잠금(lock)의 사용법 예
int InvertMatrices(IEnumerable<Matrix> matrices)
{
object mutex = new object();
int nonInvertibleCount = 0;
Parallel.ForEach(matrices, matrix =>
{
if (matrix.IsInvertible)
matrix.Invert();
else
{
lock (mutex)
{
++nonInvertibleCount;
}
}
});
return nonInvertibleCount;
}
PLINQ는 Parallel과 거의 똑같은 기능을 제공한다. 차이점:
- PLINQ는 컴퓨터의 모든 코어를 사용할 수 있다고 가정
- Prallel은 CPU의 상황에 따라 동적으로 대응
병렬 집계
int ParallelSum1(IEnumerable<int> values)
{
object mutex = new object();
int result = 0;
Parallel.ForEach(source: values,
localInit: () => 0,
body: (item, state, localValue) => localValue + item,
localFinally: localValue =>
{
lock (mutex)
result += localValue;
});
return result;
}
int ParallelSum2(IEnumerable<int> values)
{
return values.AsParallel().Sum();
}
int ParallelSum3(IEnumerable<int> values)
{
return values.AsParallel().Aggregate(
seed: 0,
func: (sum, item) => sum + item
);
}
병렬 호출
void DoAction20Times(Action action, CancellationToken token)
{
Action[] actions = Enumerable.Repeat(action, 20).ToArray();
Parallel.Invoke(
new ParallelOptions( { CancellationToken = token },
actions);
}
TPL의 핵심은 Task 형식이다.
Parallel 클래스오 PLINQ는 강력한 Task 형식을 편리하게 쓸 수 있게 감싼 wrapper일 뿐
동적 병렬 처리가 필요하다면 Task 형식을 직접 사용하는 것이 가장 쉽다.
이진 트리의 각 노드에 비용이 많이 드는 처리를 수행해야 하는 예
void Traverse(Node current)
{
DoExpensiveActionOnNode(current);
if (current.Left is not null)
ProcessNode(current.Left);
if (current.Right is not null)
ProcessNode(current.Right);
}
Task ProcessNode(Node node,
TaskCreationOptions options = TaskCreationOptions.AttachedToParent)
{
return Task.Factory.StartNew(
() => Traverse(node),
CancellationToken.None,
options,
TaskScheduler.Default);
}
void ProcessTree(Node root)
{
var task = ProcessNode(root, TaskCreationOptions.None);
task.Wait();
}
연속 작업(Continuation)
Task task = Task.Factory.StartNew(
() => Thread.Sleep(TimeSpan.FromSeconds(2)),
CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.Default);
Task continuation = task.ContinueWith(
t => Trace.WriteLine("Task is done"),
CancelltationToken.None,
TaskContinuationOptions.None,
TaskScheduler.Default);
PLINQ
IEnumerable<int> MultiplyBy2(IEnumerable<int> values)
{
return values.AsParallel().Select(value => value * 2);
}
IEnumerable<int> MultiplyBy2Ordered(IEnumerable<int> values)
{
return values.AsParallel()
.AsOrdered()
.Select(value => value * 2);
}
int ParallelSum(IEnumerable<int> values)
{
return values.AsParallel().Sum();
}
'.NET > C#' 카테고리의 다른 글
Concurrency - TPL Dataflow (0) | 2023.08.16 |
---|---|
Concurrency - Reactive Programming (0) | 2023.08.16 |
Concurrency - Asynchronous Programming (0) | 2023.08.16 |
Concurrency (동시성) (0) | 2023.08.16 |
Marshaling: 복사 및 고정 (0) | 2021.10.15 |