[UE5][C++]マルチスレッドの実装 ~ParallelFor編~
概要
UE5におけるゲーム開発では、
意識していないとどうしてもGameスレッドに処理が集中してしまいがちです。
そんな時の対策として、マルチスレッド対応が視野に入ります。
UE5では、いくつかのマルチスレッドの実装方法がありますが、
今回はParallelForを使用したマルチスレッド処理実装に焦点をあてて記事をまとめていきます。
基本的には後述の参考資料をもとに、検証したことをまとめていきたいと思います。
上記のように安定動作は確認できていないので、あらかじめご承知おきください。
参考資料
マルチスレッド対応前
今回は新規にTest(ThirdPersonCharacter)プロジェクトを作成して、
CallPrintStringというテキスト表示処理呼び出し関数と、
PrintStringというテキスト表示処理関数を追加しました。
※Characterに追加
public:
UFUNCTION(BlueprintCallable)
void CallPrintString();
void PrintString();
void ATestCharacter::CallPrintString()
{
for (int i = 0; i < 1000; i++)
{
PrintString();
}
}
void ATestCharacter::PrintString()
{
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Blue, FString("Hello"));
}
}
そして、CallPrintString関数を呼ぶための処理をレベルBPに追加しました。
マルチスレッド対応していないため、プロファイルすると単純にGameスレッドで処理されていることが分かります。
マルチスレッド対応後
上記のように、ワーカースレッドで処理されていることが確認できます。
ソースはマルチスレッド対応前の状態から以下の箇所を変更しています。
//UnrealInsightsで処理の所在を確認しやすくするため。(MULTITHREAD_COUNTERでInsights内で検索する用)
DECLARE_STATS_GROUP(TEXT("StatThread"), STATGROUP_THREAD, STATCAT_Advanced);
DECLARE_CYCLE_STAT(TEXT("MULTITHREAD_COUNTER"), STAT_MULTIHREAD_COUNTER, STATGROUP_THREAD);
void ATestCharacter::CallPrintString()
{
//ParallelForでマルチスレッド化
ParallelFor(2, [this](const int32 Index)
{
//Index=1の時に実行するようにする
//Index=0の時に実行すると、Gameスレッドでも処理が走る
if (Index != 0)
{
for (int i = 0; i < 1000; i++)
{
PrintString();
}
}
});
}
void ATestCharacter::PrintString()
{
//PrintStringの呼び出しスレッドがUnrealInsights上で分かりやすいように。
SCOPE_CYCLE_COUNTER(STAT_MULTIHREAD_COUNTER);
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Blue, FString("Hello"));
}
}
まとめ
以上簡単な説明になりますが、マルチスレッド実装方法でした。
今回は単純なテキスト表示処理呼び出しをマルチスレッド対応しただけなので、
比較的スムーズに実装が行えました。
ただ、UKismetSystemLibrary::PrintStringやその他デバッグ系の処理を、
マルチスレッド処理にするとクラッシュすることがありました。
そのあたりの検証も機会があったら、やってみたいと思います。
またUE4で試してみたら、ワーカースレッドで動かず、
ゲームスレッドのみで動いていた場合もありました(うまくマルチスレッド化できない)。
このあたりの問題についても、何か分かり次第追記したいと思います。
Discussion