Simplicity is the ultimate form of sophistication ! - Leonardo Da Vinci
UnrealEngine有了跨平台的线程、线程池和TaskGraph,再来看看Async/ParalleFor和Future/Promise的实现,由衷的感受下上面的话:简约是复杂的最终形式。这些操作实现都不复杂,却有着强大的能力,让异步并发代码写起来简洁易懂。下面简单介绍下:
- Future & Promise的实现和简单用法
- Async系列接口的用法
- Paralle接口的用法
另外这里相关接口可以类比C++标准库中的概念。UE中这些接口是基于之前提到的几种并发机制实现的,废话不多说,上代码,看注释。
1.Future & Promise
1.1.实现
Future和Promise的概念,和C++标准中的std::future/std::promise
类似:
- Future - 一个会在未来某个点返回的值
- Promise - 一个异步函数,在某个并发执行体中设置,然后Future变得有效
实现比较简单,类图如下:
TPromise<ResultType>
- PromiseTFuture<ResultType>
- FutureTFutureState<ResultType>
- Future和Promise共享的状态。- Promise创建时创建一个State
GetFuture()
时返回一个共享该状态的Future对象- 基于FEvent实现,等待和触发
1.2.基本用法
Future和Promise这两个概念非常形象,可以理解为:
- Promise - 给别人一承诺
- Promise.GetFuture() - 承诺一个未来
- Promise.SetValue(X) - 兑现承诺
- Future.IsReady() - 承诺是否兑现?
代码示例:
1 | inline void Test_FuturePromise() |
输出:
1 | LogTemp: Display: waiting for the promise... |
1.3.带回调的Promise
Promise在设置完,在进行设置操作的线程中,执行一个回调。
代码示例:
1 | inline void Test_FuturePromise2() |
输出:
1 | LogTemp: Display: TaskGraphThreadNP 0[15864], do the promise |
1.4.创建一个异步函数
定义一个返回Future的异步函数,然后拿着Future返回值,可以进行Wait/Then等操作。
定义一个异步执行的函数,并返回Future对象:
1 | TFuture<int> DoSthAsync(int Value) |
代码示例:
1 | inline void Test_FuturePromise3() |
输出:
1 | // usage1: |
2.Async接口
Async系列接口支持异步执行一个函数,并返回Future对象(包含函数返回值),可以通过参数控制使用何种UE中的并发机制。
Async执行方式:
TaskGraph
- 在TaskGraph中执行,适合运行时间较短的任务TaskGraphMainThread
- 在TaskGraph中并且指定主线程中执行,适合运行时间较短的任务Thread
- 创建一个线程对象执行,适合运行时较长的任务ThreadPool
- 在全局线程池中运行(GThreadPool
)LargeThreadPool
- Editor模式下在全局GLargeThreadPool
中运行
Async接口:
Async
- 异步执行的统一接口,需要指定执行方式(EAsyncExecution
),并返回一个Future对象AsyncThread
- 创建一个线程来执行AsyncPool
- 在指定的线程池中执行AsyncTask
- TaskGraph中指定线程类型(ENamedThreads
)中执行
代码示例1:
1 | int SimpleAsyncFunc() |
代码示例2:
1 | inline void Test_Async2() |
3.ParallelFor接口
把某一个大型任务划分成可以并行执行的N个子任务,划分方法比如采用:大的数据结构拆成块,每一块并行处理。
ParallelFor
就是用来干这个事情的(基于TaskGraph实现):
- 指定划分的数量
- 和执行函数,其中执行函数的参数为划分的索引
- 运行所有子任务直到结束,
ParallelFor
返回
代码示例:
1 | inline void Test_Parallel() |
输出:
1 | ... |
4.参考资料
完整代码示例:
UE源码:
Engine/Source/Runtime/Core/Public/Async/Future.h
Engine/Source/Runtime/Core/Public/Async/Async.h
Engine/Source/Runtime/Core/Public/Async/ParallelFor.h