我发现ue5.5对多线程进行了优化,其中一项比较大的改动就是把忙等待机制改成超额订阅机制,有个疑问,原始线程不等待时,standby线程会block,那如果原始线程触发了wait的情况,会启用standby继续代为执行,那原始线程的状态依然时自旋状态么还是会挂起,是否加重cpu线程调度消耗?
这个优化对于移动端cpu核心数量少的情况,是否是正向优化
[Attachment Removed]
我发现ue5.5对多线程进行了优化,其中一项比较大的改动就是把忙等待机制改成超额订阅机制,有个疑问,原始线程不等待时,standby线程会block,那如果原始线程触发了wait的情况,会启用standby继续代为执行,那原始线程的状态依然时自旋状态么还是会挂起,是否加重cpu线程调度消耗?
这个优化对于移动端cpu核心数量少的情况,是否是正向优化
[Attachment Removed]
Hi,
你好,我的理解oversubscription的目的是为了保持多线程的运行,因为原始现成在wait,就会让并行的线程减少,所以启动standby线程继续执行多线程任务(这个任务不是原来线程的任务,可以是any thread的task)。
因为TaskGraph在创建workerthread的时候,已经考虑了核心数量(FPlatformMisc::NumberOfWorkerThreadsToSpawn,不过Android和IOS平台最大数量是4),所以我感觉没有太大的问题。
苹果工程师建议不要使用yield来等待时间,引擎里的确有些地方用了FPlatformProcess::Sleep(0),会走到yield,task的wait应该是通过event来触发的,我的理解好像没关系?
[Attachment Removed]
对,其实就是扩充了线程池的worker数量,保证有足够线程去处理剩余的其他任务,这个我的理解和你理解是相符的。按照官方文档的对tasksystem的介绍和我看代码后的理解,使用AddNested或者AddPrerequisites或者pipe导致的wait是tasksystem级别的调度wait,不算线程级别的wait,但是如果使用task.wait/taskevent.wait的方式去做同步,这种是thread级别的wait(调用LowLevelTasks::BusyWaitUntil),内部实现我看是yield实现的,我理解的这种实现线程无法真实的block,依然要占用cpu时间片的。所以我考虑当产生wait时候,需要cpu实际调度的线程数反而增多(虽然确实提高其他task的执行的可能性),这种情况感觉可能cpu消耗更高(相当于standby执行任务+wait线程来回切换)。如果不产生wait的情况,我看standby的处理是block起来了,确实在没有wait发生的时候会保持正常cpu线程调度数量。之后我看引擎多数代码确实改成AddPrerequisites或者pipe方式实现线程依赖和共享资源竞争的处理,但依然存在着一些thread wait的调用方式。感觉这种可能会产生负面影响。 [Image Removed]第一张截图按照这个特性的配置说明,也是建议把wait换掉,如果都能不用wait,就建议把此特性关闭。第二张与第三张图是我在现在引擎里看到的用法,其实现在也是混着用的,肯定是有一些wait存在的。问题回到最开始,这样做可能会在移动端帧率更高一些,但是cpu发热会不会更严重些,我这样理解对不对?
[Attachment Removed]
Hi,
BusyWaitUntil应该已经没有使用了,5.7已经完全删掉了,(https://github.com/EpicGames/UnrealEngine/commit/90bb45ca752e22ec33a778dea47b949ab59d6b41)。
多线程的使用,肯定会增加cpu发热,如果单线程的能力已经可以满足游戏需要,肯定是减少线程更有利于控制发热。不过通常单线程不太能满足功能需求,所以只能利用多线程来减少耗时,尽量保留多的空余时间,让硬件休息。
[Attachment Removed]