• Unity场景ab包加载压缩(LZ4,LZMA)格式的测试


    情况

    最近场景越来越大,大概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 ;
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122

    大致代码分为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

    Gzip_vs_Bzip2_vs_LZMA_vs_XZ_vs_LZ4_vs_LZO

    https://segmentfault.com/a/1190000019656656

  • 相关阅读:
    MySQL学习第二部分:事务的理解
    LCR 170. 交易逆序对的总数(C语言+分治递归)
    【刷题记录15】Java工程师丨腾讯面试真题(3)
    ”只用 1 分钟“ - 超简极速 Apk 签名 & 多渠道打包神器
    超市积分管理系统(含源码+论文+答辩PPT等)
    .NET 6学习笔记(1)——通过FileStream实现不同进程对单一文件的同时读写
    java面试题之redis篇
    linux内存、cpu、进程、端口、硬盘管理
    vue 3 + TS 组合式标注类型
    α-SRHLA
  • 原文地址:https://blog.csdn.net/thinbug/article/details/134250828