PART 5 · 강의 2/4
ParallelFor 패턴
데이터 병렬 처리로 반복 작업을 가속화합니다
01
ParallelFor 개념
불균형 작업을 위한 병렬 루프
ParallelFor는 불균형 작업에 대한 범용 병렬 for로, Task Graph를 사용하여 스레드 간 더 나은 작업 분배를 제공합니다.
사용 시기
- 계산 시간이 매우 가변적인 작업
- 이번 프레임에 결과가 필요한 경우
- 몇 프레임 전의 결과를 사용할 수 없는 경우
- 대량의 독립적인 데이터 처리
02
기본 사용법
ParallelFor 구현
⚡ ParallelFor 작업 분배
Thread 0
Thread 1
Thread 2
Thread 3
Task Graph가 Items[0..N]을 코어 수만큼 자동 분배
⭐ 기본 ParallelFor
코드 숨기기
#include "Async/ParallelFor.h"
// 기본 사용
ParallelFor(Items.Num(), [&](int32 Index)
{
ProcessItem(Items[Index]);
});
단일 스레드 임계값
코드 보기
// 100개 미만이면 단일 스레드로 실행
// (오버헤드가 이득보다 큼)
ParallelFor(Items.Num(), [&](int32 Index)
{
ProcessItem(Items[Index]);
}, Items.Num() < 100); // bForceSingleThread 조건
플래그 사용
코드 보기
// 불균형 작업에 최적화
ParallelFor(Items.Num(), [&](int32 Index)
{
ProcessItem(Items[Index]);
}, EParallelForFlags::Unbalanced);
// 사용 가능한 플래그:
// - None: 기본
// - ForceSingleThread: 단일 스레드 강제
// - Unbalanced: 작업 시간이 불균형할 때
// - PumpRenderingThread: 렌더 스레드 펌핑
03
성능 비교
병렬 처리 효과
📊 10,000개 항목 처리 성능 비교
단일 스레드 for:
30ms
ParallelFor (8코어):
10ms (3배 향상!)
주의사항
ParallelFor 내에서 공유 데이터 수정 시 동기화가 필요합니다. 가능하면 각 인덱스가 독립적인 데이터만 처리하도록 설계하세요.
04
실전 예시
게임에서의 활용
⭐ NPC AI 업데이트 병렬화
코드 숨기기
void ANPCManager::UpdateAllNPCs(float DeltaTime)
{
// 각 NPC의 AI 계산을 병렬로
ParallelFor(NPCs.Num(), [&](int32 Index)
{
// 독립적인 계산만 수행
FNPCDecision Decision = NPCs[Index]->CalculateNextAction();
PendingDecisions[Index] = Decision;
});
// Game Thread에서 결과 적용
for (int32 i = 0; i < NPCs.Num(); ++i)
{
NPCs[i]->ApplyDecision(PendingDecisions[i]);
}
}
핵심 패턴
ParallelFor에서는 계산만 수행하고, UObject 수정은 Game Thread에서 순차적으로 적용합니다.
SUMMARY
핵심 요약
- ParallelFor: 대량 독립 데이터의 병렬 처리
- 임계값 설정: 소량 데이터는 단일 스레드가 효율적
- Unbalanced 플래그: 작업 시간이 불균형할 때
- 성능: 코어 수에 비례하여 최대 N배 향상
- 주의: 공유 데이터 접근 시 동기화 필요
다음 단계
다음 강의에서는 플랫폼별 최적화 전략을 다룹니다.
PRACTICE
도전 과제
배운 내용을 직접 실습해보세요
실습 1: ParallelFor 기초 실습
ParallelFor(NumElements, [](int32 Index){ ... })를 사용하여 10000개 Actor의 거리 계산을 병렬화하세요. 단일 스레드 for 루프 대비 실행 시간을 SCOPE_CYCLE_COUNTER로 비교합니다.
실습 2: 청크 사이즈 최적화
ParallelFor의 MinBatchSize 파라미터를 1, 10, 100, 1000으로 변경하며 성능을 측정하세요. 태스크 오버헤드와 부하 분산의 최적 균형점을 찾습니다.
심화 과제
FPlatformAtomics::InterlockedAdd()를 활용한 Lock-Free 카운터와 TAtomic<>를 사용하여 ParallelFor 내에서 안전하게 결과를 집계하는 시스템을 구현하세요. FCriticalSection 대비 성능 차이를 비교합니다.