Task使用备忘
UE4 Task的使用,用于备忘,快速复制
本文包括使用Task Graph、Async Task、ParallelFor
包含大量代码的Low B文章
网上讲解UE4多线程的文章有很多可以参考,配合打断点观察。这里有几个简单的使用案例:
1. Task Graph
1.1 TaskGraph_Zero.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
/*
测试TaskGraph
真正用于计算的Task
*/
class NORACOMPUTETOOLS_API FTaskGraph_Zero
{
public:
// 构造时,传入数据
FTaskGraph_Zero(int32 InTargetIndex, TArray<float>& InDataArray);
// 固定写法
FORCEINLINE TStatId GetStatId() const
{
RETURN_QUICK_DECLARE_CYCLE_STAT(FTaskGraph_Zero, STATGROUP_TaskGraphTasks);
}
// 指定运行的线程
static ENamedThreads::Type GetDesiredThread() { return ENamedThreads::AnyThread; }
// 后续执行模式(如果其它task依赖于此task执行的结果时,需要使用TrackSubsequents)
static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; }
// 执行内容
// 这里传入了线程类型和完成时触发的事件
void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& CompletionGraphEvent)
{
int32 MaxNum = TargetIndex * 100;
for (int32 i = 0; i < MaxNum; ++i)
{
DataArray[TargetIndex] += i;
}
/*
可以在DoTask中添加下面的语句确保在子Task执行完之前,CompletionGraphEvent不会触发,以保证此Task完成时,子Task也完成了
CompletionGraphEvent->DontCompleteUntil(TGraphTask<FTaskGraphClass>*->GetCompletionEvent());
还可以在此语句之后检查子Task是否已经执行完成,但不建议这么做,如果有需要可以建立依赖关系
*/
UE_LOG(LogTemp, Log, TEXT("%d"), TargetIndex);
}
private:
// 模拟数据
int32 TargetIndex;
TArray<float>& DataArray;
};
// 一个用来测试打印的委托
DECLARE_DELEGATE_OneParam(FGraphTaskDelegate, const FString&);
/*
计算完之后,用于打印的Task;也可以在这里进行下一步工作,比如再发布一批作业
*/
class NORACOMPUTETOOLS_API FTaskGraph_Zero_Print
{
public:
// 构造时,传入数据
FTaskGraph_Zero_Print(TArray<float>& InDataArray, FGraphTaskDelegate InGraphTaskDelegate, volatile bool& bInDone);
FORCEINLINE TStatId GetStatId() const
{
RETURN_QUICK_DECLARE_CYCLE_STAT(FTaskGraph_Zero_Print, STATGROUP_TaskGraphTasks);
}
static ENamedThreads::Type GetDesiredThread() { return ENamedThreads::AnyThread; }
static ESubsequentsMode::Type GetSubsequentsMode() { return ESubsequentsMode::TrackSubsequents; }
void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& CompletionGraphEvent)
{
for (auto& Value : DataArray)
{
FString message = FString::Printf(TEXT("%f"), Value);
GraphTaskDelegate.ExecuteIfBound(message);
}
bDone = true;
}
private:
TArray<float>& DataArray;
FGraphTaskDelegate GraphTaskDelegate;
volatile bool& bDone;
};
1.2 TaskGraph_Zero.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "TaskGraphs/TaskGraph_Zero.h"
FTaskGraph_Zero::FTaskGraph_Zero(int32 InTargetIndex, TArray<float>& InDataArray)
: TargetIndex(InTargetIndex), DataArray(InDataArray)
{
}
FTaskGraph_Zero_Print::FTaskGraph_Zero_Print(TArray<float>& InDataArray, FGraphTaskDelegate InGraphTaskDelegate, volatile bool& bInDone)
: DataArray(InDataArray), GraphTaskDelegate(InGraphTaskDelegate), bDone(bInDone)
{
}
1.3 测试函数
void UNoraBPLibrary::NoraPrintf(const FString& InStr)
{
UE_LOG(NoraBPLibraryLog, Log, TEXT("%s"),*InStr);
}
void UNoraBPLibrary::Nora_TG_Zero(TArray<float>& InTestArray, int32 TestArraySize)
{
// 初始化数组
InTestArray.Init(0.0, TestArraySize);
// 创建Task数组 和 依赖事件数组
TArray<TGraphTask<FTaskGraph_Zero>*> TaskArray;
FGraphEventArray PrerequisiteEvents;
// 填充
for (int32 i = 0; i < TestArraySize; ++i)
{
auto* Task = TGraphTask<FTaskGraph_Zero>::CreateTask().ConstructAndHold(i, InTestArray);
TaskArray.Add(Task);
PrerequisiteEvents.Add(Task->GetCompletionEvent());
}
volatile bool bDone = false;
// 创建打印 Task,依赖于计算Task
FGraphTaskDelegate GraphTaskDelegate = FGraphTaskDelegate::CreateStatic(&UNoraBPLibrary::NoraPrintf);
auto* PrintTask = TGraphTask<FTaskGraph_Zero_Print>::CreateTask(&PrerequisiteEvents).ConstructAndHold(InTestArray, GraphTaskDelegate, bDone);
FGraphEventRef Event = PrintTask->GetCompletionEvent();
// 触发
PrintTask->Unlock();
for (auto*& Task : TaskArray)
{
Task->Unlock();
}
while (!bDone)
{
//NoraPrintf(TEXT("Waiting...."));
}
NoraPrintf(TEXT("Done"));
}
2. Async Task
2.1 AsyncTask_Zero.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Async/AsyncWork.h"
class NORACOMPUTETOOLS_API FAsyncTask_Zero : public FNonAbandonableTask
{
friend class FAsyncTask<FAsyncTask_Zero>;
FORCEINLINE TStatId GetStatId() const
{
RETURN_QUICK_DECLARE_CYCLE_STAT(FAsyncTask_Zero, STATGROUP_ThreadPoolAsyncTasks);
}
public:
void DoWork();
FAsyncTask_Zero(int32 InTargetIndex, TArray<float>& InDataArray);
private:
int32 TargetIndex;
TArray<float>& DataArray;
};
2.2 AsyncTask_Zero.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "AsyncTasks/AsyncTask_Zero.h"
void FAsyncTask_Zero::DoWork()
{
int32 MaxNum = TargetIndex * 10000;
for (int32 i = 0; i < MaxNum; ++i)
{
DataArray[TargetIndex] += i;
}
UE_LOG(LogTemp, Log, TEXT("%d"), TargetIndex);
}
FAsyncTask_Zero::FAsyncTask_Zero(int32 InTargetIndex, TArray<float>& InDataArray)
: TargetIndex(InTargetIndex), DataArray(InDataArray)
{
}
2.3 测试函数
// 初始化数组
InTestArray.Init(0.0, TestArraySize);
TArray<FAsyncTask<FAsyncTask_Zero>*> TaskArray;
for (int32 i = 0; i < TestArraySize; ++i)
{
TaskArray.Add(new FAsyncTask<FAsyncTask_Zero>(i, InTestArray));
}
for (auto* Task : TaskArray)
{
// 可以选择线程池
Task->StartBackgroundTask();
}
for (auto* Task : TaskArray)
{
Task->EnsureCompletion();
}
for (int32 i = 0; i < TestArraySize; ++i)
{
UE_LOG(NoraBPLibraryLog, Log, TEXT("%f"), InTestArray[i]);
}
3. ParallelFor
#include "Async/ParallelFor.h"
//...........
ParallelFor(TestArraySize,
[TestArraySize](int32 CurrIdx)
{
int32 Sum = 0;
for (int32 Idx = 0; Idx < (TestArraySize - CurrIdx) * 1000; ++Idx)
{
Sum += FMath::Sqrt(34.5678910f);
}
UE_LOG(NoraBPLibraryLog, Log, TEXT("%d"), Sum);
});
TArray<int32> TestArray;
ParallelFor(TestArraySize,
[&](int32 Idx)
{
TestArray.Add(Idx);
});
UE_LOG(NoraBPLibraryLog, Log, TEXT("----------%d"), TestArray.Num());

浙公网安备 33010602011771号