[UE] 언리얼 엔진 AsyncTask 사용
AsyncTask
언리얼 엔진에는 코드를 비동기적으로 실행할 수 있는 AsyncTask라는 유용한 기능이 있습니다. 이 기능은 지정된 스레드에서 특정 코드를 실행하는 방식으로 작동하며, 주로 게임 스레드를 차단하지 않고 즉시 실행하기에는 작업이 너무 무거울 때 사용됩니다.
또한 멀티스레딩으로 인해 발생하는 문제, 특히 한 스레드에서 다른 스레드에서 사용 및/또는 수정하려는 프로퍼티에 액세스하는 문제에 대한 해결책을 제공합니다.
AsyncTask(ENamedThreads::AnyThread, []()
{
// 이 코드는 게임 스레드를 멈추지 않고 비동기적으로 실행됩니다.
});
예를 들어 비동기 작업에 대한 중첩 호출을 만들 수도 있습니다:
AsyncTask(ENamedThreads::AnyThread, []())
{
// 이 코드는 게임 스레드를 멈추지 않고 비동기적으로 실행됩니다.
AsyncTask(ENamedThreads::GameThread, []()
{
// 이 코드는 게임 스레드에서 실행됩니다.
});
});
이를 델리게이트와 결합하여 블루프린트로 코드를 비동기 실행할 수도 있습니다.
#include "Async/Async.h"
DECLARE_DYNAMIC_DELEGATE_OneParam(FAsyncDelegateExample, const TArray<float>&, OutData);
UFUNCTION(BlueprintCallable)
static void AddNumbersAsync(TArray<float> InData, const FAsyncDelegateExample& Result)
{
AsyncTask(ENamedThreads::AnyThread, [InData = MoveTemp(InData), Result]() mutable
{
for (float& InDataElement : InData)
{
InDataElement += 10;
}
AsyncTask(ENamedThreads::GameThread, [OutData = MoveTemp(InData), Result]() mutable
{
Result.ExecuteIfBound(OutData);
});
});
}
GameThread에서 실행하는 경우...
Unreal Engine에서 별도의 스레드에서 생성된 FRunnableThread 또는 그밖의 워커 스레드에서 메인 게임 스레드(GameThread)가 아닌 다른 스레드에서 Actor의 상태를 변경하려고 시도하면 동기화 문제로 인해 오류가 발생할 수 있습니다. 이를 해결하기 위해서는 GameThread에서만 Actor 상태를 변경하도록 해야 합니다.
다음 두 가지 방법을 활용하여 메인 게임 스레드에서 작업을 수행할 수 있습니다.
1. AsyncTask를 사용하여 GameThread에서 작업 실행하기
AsyncTask를 사용하면 별도의 스레드에서 GameThread에 작업을 예약할 수 있습니다. 이는 일반적으로 Lambda 함수를 통해 이루어지며, 이를 이용하여 워커 스레드에서 GameThread로 작업을 전환할 수 있습니다.
// 워커 스레드에서 GameThread로 작업을 이동하기 위한 코드 예시
AsyncTask(ENamedThreads::GameThread, [this]()
{
// 이 안에서는 GameThread에서 실행되는 코드입니다.
// Actor를 스폰하거나 상태를 변경하는 등의 작업을 안전하게 수행할 수 있습니다.
SpawnActor(...);
});
2. FGraphEventRef를 사용하여 GameThread에서 태스크 실행하기
FGraphEventRef를 사용하면 복잡한 태스크 의존성을 처리하는 고급 방식으로, 스레드 간 태스크를 스케줄링하거나 결과를 동기화할 때 유용합니다. TGraphTask를 생성하여 TFunction을 넘겨주고 GameThread에서 실행하도록 할 수 있습니다.
// 워커 스레드에서 GameThread 태스크를 생성하는 코드 예시
FGraphEventRef Task = FFunctionGraphTask::CreateAndDispatchWhenReady([]()
{
// 이 안에서는 GameThread에서 실행되는 코드입니다.
// Actor를 스폰하거나 상태를 변경하는 등의 작업을 수행합니다.
}, TStatId(), nullptr, ENamedThreads::GameThread);
두 방법 모두 GameThread에서 실행되도록 구현하여 Actor의 상태를 변경하거나 고유한 인터랙션을 게임에 통합할 수 있습니다.
이러한 방식으로 Actor의 상태를 안전하게 변경할 수 있으며, 메인 게임 스레드와 워커 스레드 간의 동기화 문제를 피할 수 있습니다.
https://georgy.dev/posts/async-task/#fnref:1
https://www.inflearn.com/questions/1084869/unreal-gamethread-%EB%AC%B8%EC%9D%98