情况
最近场景越来越大,大概800M的场景加载时间可能长达40秒左右,所以需要测试看看发生了什么。
测试环境
测试环境Win10,21thI5-12600KF,32GRam , Nvidia GF RTX2060 32G
Scene1大小:741M
加载代码
首先放上部分的加载场景的代码:
public float sceneprog;
public AsyncOperation sceneAsync;
async public Task LoadScene(string path)
{
sceneprog = 0f;
await Task.Delay(10);
StreamAssetVer sav = GameJsonMain.inst.Get(path);
if (sav == null)
{
Debug.LogWarning("不存在的场景:" + path);
return ;
}
if (!sav.isab)
{
Debug.LogWarning("场景isab必须对勾:" + path);
return;
}
float loadtime = Time.realtimeSinceStartup;
float computloadtime;
float ratetime = 0.9f;
//Application.backgroundLoadingPriority = ThreadPriority.Low;
Debug.Log("LoadScene - begin ..."+ Application.backgroundLoadingPriority);
#if UNITY_EDITOR && TESTRES
string[] dirs = UnityEditor.AssetDatabase.GetAssetPathsFromAssetBundle(path);
//Object[] listobj = new Object[dirs.Length];
if(dirs.Length == 0)
Debug.LogWarning("找不到这个资源:" + path);
for (int i = 0; i < dirs.Length; i++)
{
string assetPathAndName = dirs[i];
LoadSceneParameters ls;
ls = new LoadSceneParameters();
ls.loadSceneMode = LoadSceneMode.Additive;
sceneAsync = EditorSceneManager.LoadSceneAsyncInPlayMode(assetPathAndName,ls); // .LoadSceneInPlayMode(assetPathAndName, ls);
sceneAsync.allowSceneActivation = false;
while (sceneAsync.progress < 0.9f)
{
sceneprog = sceneAsync.progress;
await Task.Delay(100);
Debug.Log("load - " + sceneprog);
}
//sceneAsync.allowSceneActivation = true;
//listobj[i] = null;
}
sceneprog = 1f;
//Debug.Log("load1 - " + sceneprog);
computloadtime = Time.realtimeSinceStartup - loadtime;
Debug.Log("LoadScene unity- load file time : " + computloadtime);
return ;
#endif
Task<UnityWebRequest> task;
if (sav.include)
{
task = streamingAssetsLoader(sav);
}
else
{
task = AssetsLoader(sav);
}
await task;
UnityWebRequest www = task.Result;
if (www.result != UnityWebRequest.Result.Success)
{
www.Dispose();
return ;
}
computloadtime = Time.realtimeSinceStartup - loadtime;
Debug.Log("LoadScene - load file time : " + computloadtime);
//这个LoadFromFileAsync函数的路径不需要file://
AssetBundleCreateRequest abRequest;
#if UNITY_EDITOR
abRequest = AssetBundle.LoadFromFileAsync(sav.savepath.Replace(filelink, ""));
#else
if(Application.platform == RuntimePlatform.Android)
{
abRequest = AssetBundle.LoadFromFileAsync(sav.savepath);
}
else
{
abRequest = AssetBundle.LoadFromFileAsync(sav.savepath.Replace(filelink, ""));
}
#endif
abRequest.allowSceneActivation = false;
while (!abRequest.isDone)
{
sceneprog = abRequest.progress;
await Task.Delay(100);
//Debug.Log("ab:"+ sceneprog);
}
abRequest.allowSceneActivation = true;
AssetBundle ab = abRequest.assetBundle;
computloadtime = Time.realtimeSinceStartup - loadtime;
Debug.Log("LoadScene - load AssetBundle time :" + computloadtime);
//Debug.Log("ab1:ok," + sav.path +" - "+ sav.url);
sceneAsync = SceneManager.LoadSceneAsync(sav.path, LoadSceneMode.Additive);
sceneAsync.allowSceneActivation = false;
while (sceneAsync.progress < 0.9f)
{
sceneprog = ratetime + sceneAsync.progress * (1- ratetime);
await Task.Delay(100);
//Debug.Log("load:" + sceneprog);
}
sceneprog = 1f;
computloadtime = Time.realtimeSinceStartup - loadtime;
Debug.Log("LoadScene - load LoadSceneAsync time :" + computloadtime);
await Task.Delay(300);
//sceneAsync.allowSceneActivation = true;
//SceneManager.LoadScene(ab.GetAllScenePaths()[0]);
//Object[] objs = ab. ab.LoadAllAssets();
www.Dispose();
ab.Unload(false);
return ;
}
大致代码分为2部分,在编辑器下#if UNITY_EDITOR && TESTRES 使用编辑器加载方式。
首先我们直接用编辑器通过UnityEditor.AssetDatabase.GetAssetPathsFromAssetBundle(path);方法来载入,大概需要5.5-7秒时间。为什么AB包需要那么久 ?
异步和同步加载测试
所有有了下面的AB包测试。
因为是AB包下载,所以关闭宏定义TESTRES ,我在想是不是使用了AssetBundle.LoadFromFileAsync来异步加载的,所以比较慢,所以把函数改为了AssetBundle.LoadFromFile,发现:
同步LoadFromFile方式:33秒
异步LoadFromFileAsync方式:38秒
时间都挺长的,发现有一个修改后台CPU级别的函数Application.backgroundLoadingPriority。
- ThreadPriority.Low - 2ms
- ThreadPriority.BelowNormal - 4ms
- ThreadPriority.Normal - 10ms
- ThreadPriority.High - 50ms
改为了High,发现测试的结果相差不大。
压缩方式的对比
把场景的AB包我又打包成了无压缩格式和LZ4格式。我们看看测试结论
默认我的场景是LZMA格式
LZMA : 38秒
无压缩: 4.8秒
LZ4 : 4.7秒
结论
LZ4的压缩方式解压速度非常快和无压缩相差不大,压缩后大小比无压缩强的多,这种不需要从公网下载资源的推荐LZ4。
知识点
LZMA通过UnityWebRequestAssetBundle加载的LZMA格式AB包将自动重新压缩为LZ4压缩,并缓存在本地文件系统上。而通过自己写的下载方案,则可以调用AssetBundle.RecompressAssetBundleAsync API重新压缩。
参考:
https://zhuanlan.zhihu.com/p/342694796