利用多进程并行化加速Unity资源构建

栏目: 后端 · 发布时间: 6年前

内容简介:这是侑虎科技第448篇文章,感谢作者江卓浩供稿。欢迎转发分享,未经作者授权请勿转载。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群465082844)作者主页:作者也是U Sparkle活动参与者,UWA欢迎更多开发朋友加入U Sparkle开发者计划,这个舞台有你更精彩!

这是侑虎科技第448篇文章,感谢作者江卓浩供稿。欢迎转发分享,未经作者授权请勿转载。如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群465082844)

作者主页: https://github.com/jiangzhhhh

作者也是U Sparkle活动参与者,UWA欢迎更多开发朋友加入U Sparkle开发者计划,这个舞台有你更精彩!

长久以来,Unity的资源构建时间过慢是不少用户的痛点之一,特别是项目大了,构建时间更是慢得影响工作效率。

作者所在的Unity项目属于手游中的巨无霸,Assets文件夹32G,5w个资源文件,资源构建时间本来就相当感人。最近项目在准备大版本更新,引擎组正抓紧时间做优化尝试,经常性批量改贴图导入格式,导致增量构建近乎失效,每次都相当于全量构建。项目组不吝啬硬件投入,配置了比较好的打包机,但即便是在SSD+i7配置的机器上进行一次全量资源构建仍然需要5个小时(312分钟)之久。一遍“修改->打包->验证修改”的流程走完,一天时间就过去了。

作者早期发现了Unity的构建流水线无法很好地利用计算资源,具体表现为:Unity在进行构建资源时,CPU占用率、磁盘IO都非常低,计算机还有大把空闲的资源可供利用,徒增用户的等待时间。能否利用多进程并行化进行资源构建?最近尝试着实现了一下。

静心分析,要实现多进程构建需要做两件事:

- 对构建工程多开实例,保证资源跟项目设置是一致的;

- 对构建列表进行正确拆分,保证有依赖关系的资源同属同一构建任务。

如何对单个Unity工程进行实例多开呢?无法做到只能退而求其次,将工程原样复制多遍了。由于项目比较大,为了省点储存空间,作者在Windows上通过Mklink(Osx上使用ln-s),对Unity的Assets、ProjectSetting两个文件夹进行符号链接,伪装出新的工程出来。而Library文件夹不可共享,则需要由子工程自行生成。考虑到冷启动的话,初次导入资源生成Library时间可能太长,可以考虑从原始工程直接拷贝一份使用。

利用多进程并行化加速Unity资源构建

接着就需要对构建列表进行任务分组了。Unity 5开始提供的这套资源构建流水线是相当智能化的,用户只需要提供形式如AssetBundleName:[AssetName]的映射列表,而无需再像Unity 4一样手动描述AssetBundle间的依赖关系,引擎就会自动收集每个Asset依赖关系构建出正确的资源,并通过Manifest的形式给出AssetBundle间的依赖。

对构建列表进行任务分组最重要的就是必须保证有依赖关系的AssetBundle处于同一构建任务,否则会令资源被重复构建造成冗余。

利用多进程并行化加速Unity资源构建 资源C将被错误的重复打包

通过AssetDatabase.GetDependencies(asset, true)接口的运用,可以很简单地构建出资源依赖树。

遍历构建列表中的Asset,称为A;使用AssetDatabase.GetDependencies接口得出包含直接、间接的依赖Asset,称为B。检查B的Asset是否也存在于构建列表中并且属于不同的AssetBundle,则可以判定A所属的AssetBundle依赖于B所属的AssetBundle。这样我们就在真实进行构建前就得出所有AssetBundle间的依赖关系了,接下来需要将有依赖关系的AssetBundle归纳为一组。用下面的例子就能很简单说清楚:

假设构建列表中包含了ABCDEF个AssetBundle文件(AssetBundle自然又包含一个或多个Asset文件,在这层面不关心,不列出),各自的依赖关系如图。则根据依赖关系,(A,B,C),(D,E)各自必须同属一组任务,(F)了无牵挂则自为一组。

作者实现这个算法比较粗暴:

- 图中每个代表AssetBundle的节点各自独立分配到一个组;

- 遍历所有节点的依赖,将依赖节点的组跟当前节点的组合并为一个组。

利用多进程并行化加速Unity资源构建

此时,构建列表已经根据依赖情况分拆为多个任务了,一般情况下,多进程并行构建的总用时取决于此时任务列表中包含资源数目最多、计算最重的一组。

有了任务列表后,一般我们预设用于构建的子工程数目都会远小于任务数,所以需要合并任务,直到总任务数不大于子工程数为止。

合并的具体过程,我们可以顺便对任务列表做下简单的负载均衡,好让各个子工程的构建时间相对均衡一些。

作者粗略的根据资源的类型(通过文件后缀识别)分配一个预设权重值,每个构建任务中所有Asset的权重总和就是这个任务的总权重,表达了构建这个任务的计算繁重程度,每轮任务合并前先根据任务的总权重排序,每次合并权重最小的两个任务。

利用多进程并行化加速Unity资源构建

此时重要环节都做完了,将任务写成Json格式输出到子工程目录下,通过BatchMode启动Unity子进程载入子工程,读取任务Json进行构建即可。

当然,为了流水线的易用性考虑,主进程还需要等待所有子进程构建完毕后将输出结果合并汇总,便于使用者对构建结果进行跟踪。

最后,在同样SSD+i7的PC上,4个子工程+1个主工程共5节点进行并行构建,将原本需要312分钟的资源构建时间缩短至42分钟,效率提升了7.4倍。

文末,再次感谢江卓浩的分享,如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨。(QQ群:465082844)。

也欢迎大家来积极参与U Sparkle开发者计划,简称"US",代表你和我,代表UWA和开发者在一起!


以上所述就是小编给大家介绍的《利用多进程并行化加速Unity资源构建》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

七周七语言(卷2)

七周七语言(卷2)

【美】Bruce A. Tate(泰特)、Fred Daoud(达乌德)、Ian Dees(迪斯) / 7ML翻译组 / 人民邮电出版社 / 2016-12 / 59

深入研习对未来编程具有重要意义的7种语言 Lua、Factor、Elixir、Elm、Julia、Idris和MiniKanren 本书带领读者认识和学习7种编程语言,旨在帮助读者探索更为强大的编程工具。 本书延续了同系列的畅销书《七周七语言》《七周七数据库》和《七周七Web开发框架》的体例和风格。 全书共8章,前7章介绍了Lua、Factor、Elm、Elixir、Jul......一起来看看 《七周七语言(卷2)》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具