본 가정은 StreamableManager를 통한 요청에 한해서만 정리된 내용입니다.
StreamableManager 내 RequestAsyncLoad가 호출되면, RequestHandle이 생성되고, AsyncLoadingThread의 LoadPackage를 호출한다.
이후 해당 쓰레드에서 로드하고자 하는 패키지를 스트리밍하고 있는 상황에서, LoadSyncronus 요청이 들어오는 시나리오를 확인하면 다음과 같다.
1. LoadSynchronous 함수는 StreamableManager의 RequestSyncLoad 함수를 호출한다.
2. 내부적으론 아래와 같은 내용이 수행된다.
// If in async loading thread or from callback always do sync as recursive tick is unsafe
// If in EDL always do sync as EDL internally avoids flushing
// Otherwise, only do a sync load if there are no background sync loads, this is faster but will cause a sync flush
bForceSynchronousLoads = IsInAsyncLoadingThread() || IsEventDrivenLoaderEnabled() || !IsAsyncLoading();
// Do an async load and wait to complete. In some cases this will do a sync load due to safety issues
TSharedPtr<FStreamableHandle> Request = RequestAsyncLoad(MoveTemp(TargetsToStream), FStreamableDelegate(), AsyncLoadHighPriority, bManageActiveHandle, false, MoveTemp(DebugName));
bForceSynchronousLoads = false;
if (Request.IsValid())
{
EAsyncPackageState::Type Result = Request->WaitUntilComplete();
ensureMsgf(Result == EAsyncPackageState::Complete, TEXT("RequestSyncLoad of %s resulted in bad async load result %d"), *Request->DebugName, Result);
ensureMsgf(Request->HasLoadCompleted(), TEXT("RequestSyncLoad of %s completed early, not actually completed!"), *Request->DebugName);
}
return Request;
- 이때 bForceSynchronousLoads가 True로 활성화 되는 것을 확인 할 수 있다.
3. StreamableManager의 StreamInternal 내부를 확인해보면 아래와 같은 내용을 확인 할 수 있는데,
// If async loading isn't safe or it's forced on, we have to do a sync load which will flush all async loading
if (GIsInitialLoad || ThreadContext.IsInConstructor > 0 || bForceSynchronousLoads)
{
FRedirectedPath RedirectedPath;
UE_LOG(LogStreamableManager, Verbose, TEXT(" Static loading %s"), *TargetName.ToString());
Existing->Target = StaticLoadObject(UObject::StaticClass(), nullptr, *TargetName.ToString());
// Need to manually detect redirectors because the above call only expects to load a UObject::StaticClass() type
UObjectRedirector* Redir = Cast<UObjectRedirector>(Existing->Target);
if (Redir)
{
TargetName = HandleLoadedRedirector(Redir, TargetName, Existing);
}
if (Existing->Target)
{
UE_LOG(LogStreamableManager, Verbose, TEXT(" Static loaded %s"), *Existing->Target->GetFullName());
}
else
{
Existing->bLoadFailed = true;
UE_LOG(LogStreamableManager, Log, TEXT("Failed attempt to load %s"), *TargetName.ToString());
}
Existing->bAsyncLoadRequestOutstanding = false;
}
이전에 활성화한 bForceSynchronousLoads 변수가 강제적으로 동기로드로 변환하는 과정을 볼 수 있다.
따라서, 비동기 로드 중에 동기로드 요청이 들어오면, 이후 들어오는 비동기로드 요청을 동기로드로 변환하여 히치를 유발할 수 있다.