Task Graph scheduler behavior during concurrent async loading in UE5.x
0 reputation · 13 May 2023, 00:31 UTC
0 reputation · 13 May 2023, 00:31 UTC
Unreal Engine 5.x utilizes a task-based architecture where the Task Graph system manages parallel execution across worker threads. While this allows for efficient distribution of physics and animation logic, high-concurrency scenarios—specifically during the simultaneous loading of multiple actors—can introduce non-deterministic frame latency jitter.
The U-registration phase of Async Loading requires synchronization with the Game Thread. When the worker thread pool is saturated with concurrent requests, high-priority tasks may experience starvation, leading to unpredictable spikes in DeltaTime that are distinct from standard frame-budget overruns.
Given the non-deterministic nature of the scheduler when resolving complex dependency chains, what mechanisms determine task priority when the worker pool is fully saturated? Is there a documented configuration to mitigate thread starvation specifically during concurrent asset U-registration?
When the Task Graph worker pool is fully saturated, UE5 does not pre‑empt a running worker. The scheduler orders ready tasks by the following hierarchy:
Because U‑registration (the finalization that runs on the Game Thread) is serialized with the Game Thread, a saturated worker pool can cause high‑priority tasks to wait behind long lower‑priority tasks or behind an unfinished prerequisite. UE5 does not expose a dedicated CVar to “unstarve” U‑registration; the documented mitigation is to control load concurrency, keep prerequisites shallow, and avoid blocking tasks on named threads.
DeltaTime is therefore a symptom of the Game Thread being blocked by finalization, not a direct result of worker starvation.UnrealInsights.exe, enable the TaskGraph and GameThread channels, and record a few seconds of gameplay.Begin and End timestamps. Check if it is waiting for a dependency or for the Game Thread to become free.UObject::PostLoad and UObject::Register phases. If these span a large portion of the frame, the jitter originates here.AsyncLoad::SetMaxConcurrentLoads) and re‑measure. If the spike disappears, the issue is load‑concurrency‑driven.bAsyncLoad or use LoadSynchronous only when necessary.Engine/Source/Runtime/TaskGraph/Public/TaskGraphInterface.h to confirm the priority enum and any CVar defaults for your build.To refine the recommendation, please confirm: Is the stall occurring during async I/O/decompression, or during the Game Thread’s U‑registration/post‑load phase? This determines whether you should throttle I/O or restructure finalization.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.