Skip to content

UE5 비동기 & 태스크 시스템

Unreal Engine은 게임 스레드 외에 다수의 워커 스레드를 운영합니다. 무거운 연산을 백그라운드 스레드로 분산하면 게임 스레드의 프레임 시간을 절약할 수 있습니다. UE5에서는 TaskGraph, AsyncTask, UE::Tasks 세 가지 주요 API를 제공합니다.


스레드역할
Game ThreadActor Tick, 입력 처리, 블루프린트 실행
Render Thread렌더 커맨드 생성
RHI ThreadGPU 커맨드 제출
Worker ThreadsTaskGraph 작업 실행 풀

UObject·AActor·UWorld에 대한 직접 접근은 반드시 Game Thread에서만 허용됩니다.


AsyncTask — 가장 간단한 스레드 전환

Section titled “AsyncTask — 가장 간단한 스레드 전환”
// 백그라운드 스레드에서 실행
AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, []()
{
// 무거운 연산 (파일 I/O, 경로 탐색 등)
TArray<FString> Results = LoadHeavyData();
// 결과를 Game Thread로 전달
AsyncTask(ENamedThreads::GameThread, [Results = MoveTemp(Results)]()
{
// Game Thread에서 Actor 업데이트
GEngine->AddOnScreenDebugMessage(-1, 3.f, FColor::Green,
FString::Printf(TEXT("로드 완료: %d"), Results.Num()));
});
});
스레드
GameThread메인 게임 스레드
AnyBackgroundThreadNormalTask워커 스레드 (일반 우선순위)
AnyBackgroundHiPriTask워커 스레드 (높은 우선순위)
AnyThread여유 스레드 자동 선택

복수의 태스크 간 의존성(선후 관계)을 설정할 때 사용합니다.

#include "Async/TaskGraphInterfaces.h"
// 태스크 클래스 정의
class FMyTask
{
public:
static const TCHAR* GetTaskName() { return TEXT("MyHeavyTask"); }
FORCEINLINE static TStatId GetStatId()
{
RETURN_QUICK_DECLARE_CYCLE_STAT(FMyTask, STATGROUP_TaskGraphTasks);
}
static ENamedThreads::Type GetDesiredThread()
{
return ENamedThreads::AnyBackgroundThreadNormalTask;
}
static ESubsequentsMode::Type GetSubsequentsMode()
{
return ESubsequentsMode::TrackSubsequents;
}
void DoTask(ENamedThreads::Type CurrentThread,
const FGraphEventRef& MyCompletionGraphEvent)
{
// 실제 작업
HeavyComputation();
}
};
// 태스크 디스패치 및 완료 대기
FGraphEventRef Task = TGraphTask<FMyTask>::CreateTask()
.ConstructAndDispatchWhenReady();
// 의존 태스크 — Task 완료 후 실행
FGraphEventArray Prerequisites = { Task };
FGraphEventRef DependentTask = TGraphTask<FFollowUpTask>::CreateTask(&Prerequisites)
.ConstructAndDispatchWhenReady();

UE 5.1부터 도입된 경량 태스크 API로, TaskGraph보다 간결합니다.

#include "Tasks/Task.h"
using namespace UE::Tasks;
void AMyActor::RunAsyncWork()
{
// 백그라운드 태스크 실행
FTask Task = Launch(TEXT("HeavyWork"),
[]() -> int32
{
return PerformHeavyCalculation();
});
// 태스크 완료 후 콜백 (파이프라인)
Launch(TEXT("ProcessResult"),
[Task]()
{
int32 Result = Task.GetResult();
// 주의: 여기도 워커 스레드 — UObject 접근 불가
},
Prerequisites(Task));
}
FTask Task = Launch(TEXT("Work"), []() { HeavyWork(); });
// Game Thread에서 블로킹 대기 — 프레임 드롭 주의
Task.Wait();
// 또는 완료 여부만 확인
if (Task.IsCompleted()) { ... }

UE5는 C++ 코루틴을 지원하지 않지만, 플러그인 UE5Coro 또는 PromiseAPI를 활용하면 유사한 패턴을 구현할 수 있습니다. 공식적으로는 Latent Action이 대안입니다.

// Latent Action — Blueprint에서도 사용 가능한 비동기 노드
UFUNCTION(BlueprintCallable, meta=(Latent, LatentInfo="LatentInfo"))
void LoadDataAsync(FLatentActionInfo LatentInfo, FString Path, FString& OutResult)
{
if (UWorld* World = GetWorld())
{
FLatentActionManager& Manager = World->GetLatentActionManager();
if (!Manager.FindExistingAction<FMyLatentAction>(
LatentInfo.CallbackTarget, LatentInfo.UUID))
{
Manager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID,
new FMyLatentAction(Path, OutResult, LatentInfo));
}
}
}

// ✅ 워커 스레드에서 안전한 작업
- 순수 수학 연산
- TArray / TMap 로컬 복사본 조작
- FString 생성·파싱
- 파일 I/O (IPlatformFile)
// ❌ 워커 스레드에서 금지
- UObject 생성·접근 (NewObject, GetWorld 등)
- Actor Spawn / Destroy
- UE_LOG (스레드 안전하지 않은 버전)
- Slate / UMG UI 접근