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

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

内容简介:这是侑虎科技第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资源构建》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

Java Concurrency in Practice

Java Concurrency in Practice

Brian Goetz、Tim Peierls、Joshua Bloch、Joseph Bowbeer、David Holmes、Doug Lea / Addison-Wesley Professional / 2006-5-19 / USD 59.99

This book covers: Basic concepts of concurrency and thread safety Techniques for building and composing thread-safe classes Using the concurrency building blocks in java.util.concurrent Pe......一起来看看 《Java Concurrency in Practice》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

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

HEX HSV 互换工具