虚幻4 Task Graph System 介绍

taskgraphsystemuml

引言

Task Graph System是虚幻4核心模块中的一层抽象任务处理系统,
通过该基础设施,我们可以创建任意多线程任务, 异步任务, 序列任务, 并行任务等,并可以指定任务顺序, 设置任务间的依赖, 最终形成一个任务图, 该系统按照设定好的依赖关系来分配任务图中的任务到各个线程中执行, 最终执行完整个任务图。

Thread

引擎会根据平台多线程支持情况创建一组线程。在支持多线程的平台上,通常会各有一个NamedThread,多个AnyThread。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace ENamedThreads
{
enum Type
{
UnusedAnchor = -1,
/** The always-present, named threads are listed next **/
#if STATS
StatsThread,
#endif
RHIThread, // 创建一个
AudioThread, // 创建一个
GameThread, // 创建一个
// 不支持多线程的平台(如HTML5) 渲染线程为GameThread, 支持多线程的平台 渲染线程为ActualRenderingThread
ActualRenderingThread = GameThread + 1, // 创建一个
// CAUTION ThreadedRenderingThread must be the last named thread, insert new named threads before it

/** not actually a thread index. Means "Unknown Thread" or "Any Unnamed Thread" **/
AnyThread = 0xff

Task

模板类TGraphTask<TTask> 中类型参数TTask应提供下面几个函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class TTask {

IStatId GetStatId() const;

// 在哪个线程执行该任务? NamedThread 或 AnyThread
[static] ENamedThreads::Type GetDesiredThread();
/*
namespace ESubsequentsMode
{
enum Type
{
// 存在后续任务
TrackSubsequents,
// 没有后续任务依赖该任务
FireAndForget
};
}
*/

static ESubsequentsMode::Type GetSubsequentsMode();
//在该函数中执行具体任务内容
void DoTask(ENamedThreads::Type, const FGraphEventRef&);
}

FTaskGraphInterface为Task Graph System接口, 负责调度执行任务
FTaskGraphInterface对用户透明,通常使用TGraphTask::CreateTask()创建任务

首先要定义任务类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class FHeavyTask 
{
int32 LoopCount;
public:
FHeavyTask(int count): LoopCount{count}
{}
~FHeavyTask(){}
IStatId GetStatId() const
{

RETURN_QUICK_DECLARE_CYCLE_STAT(FHeavyTask, STATGROUP_TaskGraphTasks);
}

static ENamedThreads::Type GetDesiredThread()
{

return ENamedThreads::AnyThread;
}

static ESubsequentsMode::Type GetSubsequentsMode()
{

return ESubsequentsMode::FireAndForget;
}

void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent)
{

// Do real task
}
};
```
创建任务并分发
```cpp
TGraphTask<FHeavyTask>::CreateTask().ConstructAndDispatchWhenReady(100);

ParallelFor

基于TaskGraphSystem的ParallelFor函数,我们可以把某些for循环并行化

1
2
3
4
// 并行执行多个Function
void ParallelFor(int32 Num, TFunctionRef<void(int32)> Body, bool bForceSingleThread = false);

void ParallelForWithPreWork(int32 Num, TFunctionRef<void(int32)> Body TFunctionRef<void()> CurrentThreadWorkToDoBeforeHelping, bool bForceSingleThread = false);

举个栗子:

1
2
3
4
5
6
7
8
9
10
TArray<FString> IntStringArray;
Fill(IntStringArray); // fill IntStringArray
TArray<int32> IntArray;
IntArray.SetNum(IntStringArray.Num());
auto mapper = [&](int32 idx) {
IntArray[idx] = FCString::Atoi(*IntStringArray[idx]);
};

// 并行化
ParallelFor(IntStringArray.Num(), mapper);

Async

1
2
//异步执行一个Function 
void AsyncTask(ENamedThreads::Type Thread, TFunction<void()> Function);

Conclusion

End