U3D客户端框架(资源管理篇)之资源热更新管理器 ResourceManager

news2024/11/21 0:39:37

一、资源热更新管理器模块设计

1.热更新是什么?

游戏或者软件内的 美术/脚本代码等资源 发生变化时,无需下载客户端重新进行安装,而是在应用程序启动的情况下,通过比对本地资源与CDN资源的MD5码,如果本地资源与CDN中的资源有差异,则优先使用CDN中的资源,以增量的方式进行下载更新这些变化了的 美术/脚本代码等资源。

2.热更新的商业价值

根据经验判断,每次强制用户换包将会造成 5%-15%+ 的用户流失,所以热更新对于商业价值来说是必要的。一个合格的产品采用热更新的方式更新资源是必要的。

3.资源热更新管理器 UML类静态视图

在这里插入图片描述


4.资源热更新管理器 网络拓扑图

在这里插入图片描述

5.热更新流程

1.启动游戏

2.初始化只读区资源版本和文件列表

3.获取CDN上的资源版本和文件列表

4.可写区是否有版本文件存在,如果没有,则拷贝资源版本和文件列表到可写区,不会把只读区的所有文件都往可写区都拷贝一份,不然太大了,可写区只存放增量资源。

5.可写区资源版本与CDN资源版本进行比对,如果版本号不一致进行资源比对

6.下载差异文件到可写区:1).可写区的MD5和CDN的MD5不一致并且只读区没有这个文件;
2).可写区的MD5和CDN的MD5不一致,只读区MD5和CDN MD5也不一致;
3).初始资源,可写区和只读区都没有;
4).初始资源,可写区没有,但是CDN上的MD5和只读区的MD5又不一致;
以上情况需要下载。

7.下载完成进入预加载流程。


二、代码设计

热更新管理器(ResourceManager)完整代码

    //热更新管理器
    public class ResourceManager : ManagerBase, IDisposable
    {
        #region 静态区域
        /// <summary>
        /// GetAssetBundleVersionList  根据字节数组获取资源包版本信息
        /// 根据字节数组,获取资源包版本信息
        /// </summary>
        public static Dictionary<string, AssetBundleInfoEntity> GetAssetBundleVersionList(byte[] buffer, ref string version)
        {
            //使用zlib解压数据
            buffer = ZlibHelper.DeCompressBytes(buffer);

            //构造map
            Dictionary<string, AssetBundleInfoEntity> dic = new Dictionary<string, AssetBundleInfoEntity>();

            //使用buffer数组,初始化内存流对象
            MMO_MemoryStream ms = new MMO_MemoryStream(buffer);

            //assetbundle包的数量
            int len = ms.ReadInt();

            for (int i = 0; i < len; ++i)
            {
                //版本信息在完整数据的第二段
                if (i == 0)
                {
                    //删除字符串头部和尾部的所有空格,
                    //但是字符串中间的空格是不能被删去的。
                    version = ms.ReadUTF8String().Trim();
                }
                else
                {
                    AssetBundleInfoEntity entity = new AssetBundleInfoEntity();
                    entity.AssetBundleName = ms.ReadUTF8String();
                    entity.MD5 = ms.ReadUTF8String();
                    entity.Size = ms.ReadULong();
                    entity.IsFirstData = ms.ReadByte() == 1;
                    entity.IsEncrypt = ms.ReadByte() == 1;

                    dic[entity.AssetBundleName] = entity;
                }
            }
            return dic;
        }
        #endregion

        //只读区管理器(其实看这个名字,我以为StreamingAsset才是可写区,LocalAsset是只读区)
        public StreamingAssetsManager StreamingAssetsManager
        {
            get;
            private set;
        }

        //可写区管理器
        public LocalAssetsManager LocalAssetsManager
        {
            get;
            private set;
        }

        //需要下载的资源包列表
        private LinkedList<string> m_NeedDownloadList;

        //检查版本更新下载时候的参数
        private BaseParams m_DownloadingParams;

        //只读区变量
        private string m_StreamingAssetVersion;

        //只读区资源包(ab包)信息
        private Dictionary<string, AssetBundleInfoEntity> m_dicStreamingAssetsVersion = new Dictionary<string, AssetBundleInfoEntity>();

        //是否存在只读区资源包信息(只读区有资源包吗?是这个意思吗?默认不存在?)
        private bool m_IsExistStreamingAssetsBundleInfo = false;

        private string m_LocalAssetsVersion;

        //可写区资源包信息
        private Dictionary<string, AssetBundleInfoEntity> m_dicLocalAssetsVersion = new Dictionary<string, AssetBundleInfoEntity>();


        //CDN
        //CSN资源版本号
        private string m_CDNVersion;

        //CDN资源版本号
        public string CDNVersion
        {
            get { return m_CDNVersion; }
        }

        //cdn资源包信息
        private Dictionary<string, AssetBundleInfoEntity> m_dicCDNVersion = new Dictionary<string, AssetBundleInfoEntity>();



        public ResourceManager()
        {
            StreamingAssetsManager = new StreamingAssetsManager();
            LocalAssetsManager = new LocalAssetsManager();
            m_NeedDownloadList = new LinkedList<string>();
        }

        public override void Init()
        {

        }

        #region 只读区
        //初始化只读区资源包信息
        public void InitStreamingAssetsBundleInfo()
        {
            ReadStreamingAssetsBundle(ConstDefine.VersionFileName, (byte[] buffer) =>
            {
                //只读区没有版本文件,初始化Cdn
                if (null == buffer)
                {
                    InitCDNAssetBundleInfo();
                }
                //只读区有版本文件,拿到本地的版本信息
                else
                {
                    m_IsExistStreamingAssetsBundleInfo = true;
                    m_dicStreamingAssetsVersion = GetAssetBundleVersionList(buffer, ref m_StreamingAssetVersion);
                    InitCDNAssetBundleInfo();
                }
            });

        }

        //读取只读区的资源包
        internal void ReadStreamingAssetsBundle(string fileUrl, BaseAction<byte[]> onComplete)
        {
            StreamingAssetsManager.ReadAssetBundle(fileUrl, onComplete);
        }

        #endregion

        #region 可写区
        //检查可写区版本文件是否存在
        private void CheckVersionFileExistsInLocal()
        {
            //输出流程log
            GameEntry.Log(LogCategory.Resource, " CheckVersionFileExistsInLocal ");

            //可写区有版本文件存在 
            if (LocalAssetsManager.GetVersionFileExists())
            {
                //加载可写区资源包信息
                InitLocalAssetsBundleInfo();
            }
            //可写区无版本文件
            else
            {
                //判断只读区 版本文件是否存在
                //如果只读区 版本文件存在
                if (m_IsExistStreamingAssetsBundleInfo)
                {
                    //将只读取的版本文件 copy到可写区
                    InitVersionFileFromStreamingAssetsToLocal();
                }
                
                //检查是否需要热更
                CheckVersionChange();
            }

        }

        //将只读区的文件信息初始化到可写区(copy to)
        private void InitVersionFileFromStreamingAssetsToLocal()
        {
            GameEntry.Log(LogCategory.Resource, "InitVersionFileFromStreamingAssetsToLocal");

            m_dicLocalAssetsVersion.Clear();
            //m_dicLocalAssetsVersion = new Dictionary<string, AssetBundleInfoEntity>();

            //把只读区的文件信息拷贝到可写区
            IEnumerator<KeyValuePair<string, AssetBundleInfoEntity>> iter =m_dicStreamingAssetsVersion.GetEnumerator();
            while (iter.MoveNext())
            {
                string assetBundleName = iter.Current.Key;
                AssetBundleInfoEntity entity = iter.Current.Value;
                m_dicLocalAssetsVersion[assetBundleName] = new AssetBundleInfoEntity()
                {
                    AssetBundleName = entity.AssetBundleName,
                    MD5 = entity.MD5,
                    Size = entity.Size,
                    IsFirstData = entity.IsFirstData,
                    IsEncrypt = entity.IsEncrypt,
                };
            }

            //保存可写区的版本文件
            LocalAssetsManager.SaveVersionFile(m_dicLocalAssetsVersion);

            //保存可写区的资源版本号,= 只读取的资源版本号
            m_LocalAssetsVersion = m_StreamingAssetVersion;

            //可写区管理器 保存 可写区的资源版本号
            LocalAssetsManager.SetResourceVersion(m_LocalAssetsVersion);
        }

        //初始化可写区的资源包信息
        private void InitLocalAssetsBundleInfo()
        {
            GameEntry.Log(LogCategory.Resource, "InitLocalAssetsBundleInfo");

            //拿到可写区的文件列表
            m_dicLocalAssetsVersion = LocalAssetsManager.GetAssetBundleVersionList(ref m_LocalAssetsVersion);

            //检查文件是否改变
            CheckVersionChange();
        }

        public void SaveVersion(AssetBundleInfoEntity entity)
        {

        }

        //保存资源版本号(用于检查版本,更新完毕后保存)
        public void SetResourceVersion()
        {
            //本地的版本=cdn上的版本
            m_LocalAssetsVersion = m_CDNVersion;
            LocalAssetsManager.SetResourceVersion(m_LocalAssetsVersion);
        }
        #endregion

        #region CDN
        //初始化CDN资源包信息
        private void InitCDNAssetBundleInfo()
        {
            StringBuilder sbr = StringHelper.PoolNew();
            string url = sbr.AppendFormatNoGC("{0}{1}", GameEntry.Data.SysDataManager.CurrChannelConfig.RealSourceUrl, ConstDefine.VersionFileName).ToString();
            StringHelper.PoolDel(ref sbr);
            GameEntry.Log(LogCategory.Resource, url);
            GameEntry.Http.SendData(url, OnInitCDNAssetBundleInfo, isGetData: true);
        }

        //初始化CDN资源包信息回调(访问版本资源之后的http回调)
        private void OnInitCDNAssetBundleInfo(HttpCallBackArgs args)
        {
            GameEntry.Log(LogCategory.Normal," OnInitCDNAssetBundleInfointo");
            if (!args.HasError)
            {
                m_dicCDNVersion = GetAssetBundleVersionList(args.Data, ref m_CDNVersion);

                GameEntry.Log(LogCategory.Resource, "OnInitCDNAssetBundleInfo");

                //检查本地的版本文件
                CheckVersionFileExistsInLocal();
            }
            else
            {
                GameEntry.Log(LogCategory.Resource, args.Value);
            }
        }
        #endregion

        //获取资源包信息(返回CDN上的资源信息)
        public AssetBundleInfoEntity GetCDNAssetBundleInfo(string assetBundlePath)
        {
            AssetBundleInfoEntity entity = null;
            m_dicCDNVersion.TryGetValue(assetBundlePath, out entity);
            return entity;
        }

        #region 检查更新&下载更新
        //检查更新
        private void CheckVersionChange()
        {
            GameEntry.Log(LogCategory.Resource, " CheckVersionChange");

            //可写区存在版本文件(filelist文件)
            if (LocalAssetsManager.GetVersionFileExists())
            {
                //判断只读区资源版本号 和 CDN资源版本号是否一致
                if (!string.IsNullOrEmpty(m_LocalAssetsVersion) && m_LocalAssetsVersion.Equals(m_CDNVersion))
                {
                    GameEntry.Log(LogCategory.Resource, " 可写区资源保本和CDN资源版本号 一致");

                    //一致 进入预加载流程
                    GameEntry.Procedure.ChangeState(ProcedureState.Preload);
                }
                else
                {
                    GameEntry.Log(LogCategory.Resource, " 可写区资源保本和CDN资源版本号 不一致");

                    //不一致,本地文件列表和CDN上的文件列表做比对
                    GameEntry.Log(LogCategory.Normal, "out BeginCheckVersionChange1.0");
                    BeginCheckVersionChange();
                }
            }
            //不存在filelist文件,下载初始资源
            else
            {
                GameEntry.Log(LogCategory.Resource, "下载初始资源");
                DownloadInitResources();   
            }
        }

        //下载初始资源
        private void DownloadInitResources()
        {
            //TODO:派发 检查版本开始下载 事件
            m_DownloadingParams = GameEntry.Pool.DequeueClassObject<BaseParams>();
            m_DownloadingParams.Reset();

            m_NeedDownloadList.Clear();

            IEnumerator<KeyValuePair<string, AssetBundleInfoEntity>> iter = m_dicCDNVersion.GetEnumerator();
            while (iter.MoveNext())
            {
                AssetBundleInfoEntity entity = iter.Current.Value;

                //下载初始资源包
                if (entity.IsFirstData)
                {
                    m_NeedDownloadList.AddLast(entity.AssetBundleName);
                } 
            }

            if (m_NeedDownloadList.Count == 0)
            {
                BeginCheckVersionChange();
            }
            else
            {
                GameEntry.Download.BeginDownloadMulti(m_NeedDownloadList, OnDownloadMultiUpdate, OnDownloadMultiComplete);
            }
        }

        //开始检查更新
        private void BeginCheckVersionChange()
        {
            m_DownloadingParams = GameEntry.Pool.DequeueClassObject<BaseParams>();
            m_DownloadingParams.Reset();

            LinkedList<string> lstDel = new LinkedList<string>();

            LinkedList<string> lstInconformity = new LinkedList<string>();

            LinkedList<string> lstNeedDownload = new LinkedList<string>();

            #region 找出需要删除的文件,然后删除
            //一、寻找有差异的,需要删除的、需要下载的文件
            IEnumerator<KeyValuePair<string, AssetBundleInfoEntity>> iter = m_dicLocalAssetsVersion.GetEnumerator();

            //第一次循环:对可写区的文件循环
            while (iter.MoveNext())
            {
                string assetBundleName = iter.Current.Key; 
                AssetBundleInfoEntity cdnAssetBundleInfoEntity = null;
                if (m_dicCDNVersion.TryGetValue(assetBundleName, out cdnAssetBundleInfoEntity))
                {
                    //本地有,CDN也有的,对比资源是否一致,不一致加入不一致列表
                    if (cdnAssetBundleInfoEntity.MD5.Equals(iter.Current.Value.MD5, StringComparison.CurrentCultureIgnoreCase))
                    {
                        lstInconformity.AddLast(assetBundleName);
                    }
                }
                else
                {
                    //CDN没有的,本地也删除
                    lstDel.AddLast(assetBundleName);
                } 
                
                LinkedListNode<string> iterInconformity = lstInconformity.First;
                while (iterInconformity != null)
                {
                    //差异文件
                    string inconformityFile = iterInconformity.Value;

                    //cdn中的ab包文件信息
                    AssetBundleInfoEntity cdnAssetBundleInfo = null;
                    m_dicCDNVersion.TryGetValue(inconformityFile, out cdnAssetBundleInfo);

                    AssetBundleInfoEntity streamingBundleInfo = null;
                    m_dicStreamingAssetsVersion.TryGetValue(inconformityFile, out streamingBundleInfo);
 
                    if (null == streamingBundleInfo)
                    {
                        //只读区没有
                        lstNeedDownload.AddLast(inconformityFile);
                    }
                    else
                    {
                        //只读区有,判断CDN中该文件的MD5和只读区的是否一致,如果一致,说明版本回退了。删掉可写区的,用只读区的
                        if (cdnAssetBundleInfo.MD5.Equals(streamingBundleInfo.MD5, StringComparison.CurrentCultureIgnoreCase))
                        {
                            //一致
                            lstDel.AddLast(inconformityFile);
                        }
                        else
                        {
                            //不一致,下载
                            lstNeedDownload.AddLast(inconformityFile);
                        }
                    }

                    iterInconformity = iterInconformity.Next;
                }
            }

            //二、删除需要删除的文件
            //第2.1次循环:删除需要删除的文件
            for (LinkedListNode<string> iterNeedDelFile = lstDel.First; iterNeedDelFile != null;)
            {
                StringBuilder sbr = StringHelper.PoolNew();
                string filePath = sbr.AppendFormatNoGC("{0}/{1}", GameEntry.Resource.LocalFilePath, iterNeedDelFile.Value).ToString();
                StringHelper.PoolDel(ref sbr);

                //删除文件
                if (File.Exists(filePath))
                {
                    File.Delete(filePath);
                }

                LinkedListNode<string> next = iterNeedDelFile.Next;
                lstDel.Remove(iterNeedDelFile);
                iterNeedDelFile = next;
            }
            #endregion

            #region 检查需要下载的

            //第3次循环:对CDN站点上的资源进行循环
            iter = m_dicCDNVersion.GetEnumerator();
            while (iter.MoveNext())
            {
                AssetBundleInfoEntity cdnAssetBundleInfo = iter.Current.Value;

                //如果是初始资源
                if (cdnAssetBundleInfo.IsFirstData)
                {
                    //检查初始资源
                    //如果可写区没有CDN上的初始资源
                    if (!m_dicLocalAssetsVersion.ContainsKey(cdnAssetBundleInfo.AssetBundleName))
                    {
                        //如果可写区没有CDN上的这个资源文件,则去只读区检查一下
                        AssetBundleInfoEntity streamingAssetBundleInfo = null;
                        if (null != m_dicStreamingAssetsVersion)
                        {
                            m_dicStreamingAssetsVersion.TryGetValue(cdnAssetBundleInfo.AssetBundleName, out streamingAssetBundleInfo);
                        }

                        //只读区也不存在,需要下载
                        if (null == streamingAssetBundleInfo)
                        {
                            lstNeedDownload.AddLast(cdnAssetBundleInfo.AssetBundleName);
                        }
                        else
                        {
                            //如果只读区的MD5和CDN上的MD5数据不一致
                            if (!cdnAssetBundleInfo.MD5.Equals(streamingAssetBundleInfo.MD5, StringComparison.CurrentCultureIgnoreCase))
                            {
                                //MD5不一致
                                lstNeedDownload.AddLast(cdnAssetBundleInfo.AssetBundleName);
                            }
                        }
                    }
                }
            }
            #endregion

            //TODO:发送版本开始检查的事件
            //GameEntry.

            //进行下载
            GameEntry.Download.BeginDownloadMulti(lstNeedDownload, OnDownloadMultiUpdate, OnDownloadMultiComplete);
        }


        /* 
         * 函数功能:下载中的回调
         * t1:当前下载数量
         * t2:总文件数量
         * t3:当前下载的大小(单位:字节)
         * t4:总下载大小(单位:字节)
         */
        private void OnDownloadMultiUpdate(int t1, int t2, ulong t3, ulong t4)
        {
            m_DownloadingParams.IntParam1 = t1;
            m_DownloadingParams.IntParam2 = t2;

            m_DownloadingParams.ULongParam1 = t3;
            m_DownloadingParams.ULongParam2 = t4;

            //GameEntry.Log(LogCategory.Resource,"t1:{0} t2:{1} t3:{2} t4:{3}",t1,t2,t3,t4);

            GameEntry.Event.CommonEvent.Dispatch(SysEventId.CheckVersionDownloadUpdate, m_DownloadingParams);
        }

        //下载完毕
        private void OnDownloadMultiComplete()
        {
            //设置资源版本
            SetResourceVersion();

            //检查版本更新下载成功 事件
            GameEntry.Event.CommonEvent.Dispatch(SysEventId.CheckVersionDownloadComplete);

            GameEntry.Pool.EnqueueClassObject(m_DownloadingParams);

            GameEntry.Procedure.ChangeState(ProcedureState.Preload);
        }
        #endregion


        public void Dispose()
        {
            if (m_dicStreamingAssetsVersion != null)
            {
                m_dicStreamingAssetsVersion.Clear();
            }

            if (m_dicLocalAssetsVersion != null)
            {
                m_dicLocalAssetsVersion.Clear();
            }
        }

    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/147269.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Visual Code 打开方式添加到右键菜单

一、配置右键打开 文件 注册表找到分支&#xff1a; 计算机\HKEY_CLASSES_ROOT\*\shell 在这个里面 shell 分支里右键添加项 VisualCode&#xff08;这个可以随便起&#xff0c;便于识别就行&#xff09; 在 VisualCode 分支里右键添加项 Command&#xff08;必须这个名&am…

【C++】双指针用法

快慢指针/同向指针 [0,i)的数据代表处理好的数据[i,j)的数据是那些处理过但不需要的数据[j,array.length)区间的数据为接下来待处理的数据。 以上三个区间的开和闭需要根据题目要求定义&#xff0c;但是要保持一致。 用此方法处理过的数组&#xff0c;处理好的数据相对位置会保…

(mysql)Waiting for table metadata lock

MySQL5.5 中引入了 metadata lock. 顾名思义&#xff0c;metadata lock 不是为了保护表中的数据的&#xff0c;而是保护 database objects(元数据)的。包括表结构、schema、存储过程、函数、触发器、mysql的调度事件(events). 要理解 metadata lock 最重要的一点就是&#xff1…

python连接mysql之PyMySQL的基本使用

一、PyMySQL的基本使用使用pymysql 直接连接mysqlPyMySQL安装pip3 install pymysqlimport pymysql# 连接数据库&#xff0c;创建连接对象connection # 连接对象作用是&#xff1a;连接数据库、发送数据库信息、处理回滚操作&#xff08;查询中断时&#xff0c;数据库回到最初状…

关于Docker如何安装nginx

目录 1.Nginx 1.2. 安装nginx 2.容器之间相互通信 2.1.两个容器在同一网段 2.2.两个容器在不同网段 1.Nginx Nginx也是一款服务器&#xff0c;我们常用它做如&#xff1a;反向代理、负载均衡、动态与静态资源的分离的工作 反向代理&#xff1a;反向代理&#xff08;Revers…

java spring下载步骤

首先 我们要下载一下 spring 我们访问spring的官网 地址非常的好记 spring.io project进入官网我们选择 project>Spring Framework 进入界面 我们选择 Learn 下面就会给我们列举出版本 这边建议大家下5.3.24 首先 要下GA的 因为这表示它比较稳定 其次 版本比较适中 大部分…

黑客动态播报 | 2023年网络攻击趋势

今天是跨入2023年大门的第一个工作日,作为开年的第一篇内容,我们从安全说起。      自2020年勒索软件攻击呈爆发式增长以来,全球企业都经历了“噩梦”般的三年,层出不穷的手段和无孔不入的方式,都让我们绷紧了每一条神经。      而在这三年里,我们并不是疲于应对,通过不…

过年了,怎么样批量爬取某东商品信息,并做可视化

前言 马上就要过年了&#xff0c;大家都在屯年货了网络上商品信息太多&#xff0c;不知道如何选择&#xff0c;今天&#xff0c;我们就用python爬取商品信息&#xff0c;并做可视化。 环境使用 python 3.9pycharm 模块使用 requestsseleniumtime谷歌驱动 说明 一、谷歌驱动…

前端学习之BootStrap

前言 Bootstrap 最初是由 mdo 和 fat 于 2010 年中旬创造就职于 Twitter 时创造的。在成为开源框架之前&#xff0c;Bootstrap 被称为 Twitter Blueprint。经过几个月的开发&#xff0c;Twitter 举办了首届黑客周&#xff08;Hack Week&#xff09;&#xff0c;该项目获得了爆…

基于Java+SpringBoot+vue+elementUI私人健身教练预约管理系统设计实现

基于JavaSpringBootvueelementUI私人健身教练预约管理系统设计实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留…

Linux中的文件描述符

目录 文件描述符 系统调用 open 为什么fd从3开始呢&#xff1f; 为什么是0,1,2,3...呢&#xff1f; 文件描述符分配规则 系统调用 close 系统调用 wirte 系统调用 read 文件描述符 在了解文件描述符之前&#xff0c;先了解关于操作文件的系统调用&#xff0c;C语言中的f…

Spring Cloud整体架构

Spring Cloud的中文名我们就暂且称呼它为“春云”吧&#xff0c;听上去是多么朴实无华的名字&#xff0c;不过呢一般名字起的低调的都是厉害角色&#xff0c;我们就看看Spring Cloud都提供了哪些靠谱功能吧。 技多不压身 我们前面说过&#xff0c;Spring Cloud是一款微服务架…

Aspect-based Sentiment Analysis with Opinion Tree Generation 论文阅读笔记

一、作者 Xiaoyi Bao、Wang Zhongqing、 Xiaotong Jiang、 Rong Xiao、Shoushan Li Natural Language Processing Lab, Soochow University, Suzhou, China Alibaba Group, Hangzhou, China 二、背景 作为细粒度的情感分析任务&#xff0c;ABSA 涉及了多个基本情感元素&am…

(八)汇编语言——数据处理的两个基本问题

目录 用于内存寻址的寄存器 bp 组合 两个基本问题 数据位置 立即数 寄存器 内存 数据长度 除法指令 dup指令 总结 接下来&#xff0c;我们要处理的是有关数据处理的两个基本问题&#xff0c;那么这两个基本问题是什么呢&#xff1f;我们先告诉大家这两个问题&#…

《操作系统-真象还原》15. 系统交互

文章目录fork 的原理与实现简介什么是 forkfork 的实现思路代码get_a_page_without_opvaddrbitmapcopy_pcb_vaddrbitmap_stack0copy_body_stack3build_child_stackupdate_inode_open_cntscopy_processsys_fork添加 fork 系统调用与实现 init 进程添加 fork 系统调用实现 init 进…

计算机网络复习之DL层(数据链路层)与LAN(Local Area Network局域网)

文章目录封装成帧透明传输字符计数法字符填充法零比特填充法违规编码法差错控制透明网桥网桥自学习转发表网桥的自学习和转发帧的步骤透明网桥工作原理交换机/路由器的广播域、冲突域冲突域广播域交换机/路由器的两域区别CSMA/CD协议PPP协议HDLC协议PPP和HDLC的对比简述IEEE802…

2. 数据类型、向量、向量索引、向量修改、向量运算

课程视频链接&#xff1a;https://www.bilibili.com/video/BV19x411X7C6?p1 本笔记参照该视频&#xff0c;笔记顺序做了些调整【个人感觉逻辑顺畅】&#xff0c;并删掉一些不重要的内容 系列笔记目录【持续更新】&#xff1a;https://blog.csdn.net/weixin_42214698/category_…

【学习】Q learning、Q-learning for continuous actions、关于深度学习的猜想

文章目录一、Q learning评估状态值函数Vπ(s)MCTDdouble DQNdueling DQNprioritized replymulti-stepnoisy netdistributionalrainbow二、Q-learning for continuous actions三、关于深度学习的猜想一、Q learning value-based的方法&#xff0c;评论家不会直接决定行动。给定…

低度酒“百家争鸣”,谁能俘获年轻人的芳心?

【潮汐商业评论/原创】随着消费升级和女性消费力量的崛起&#xff0c;“她经济”逐渐成为新零售消费环境下一道“靓丽风景线”。女性消费者的消费偏好和消费习惯&#xff0c;正在促使低度酒、食品、服装、护肤、美妆、家居、育儿等行业发生新的变革。特别是酒水市场&#xff0c…

Spring Boot学习篇(八)

Spring Boot学习篇(八) 1.thymeleaf模板引擎使用篇(二) 1.1 配置通过地址栏直接访问html页面 1.1.1 在zlz包下创建filter包,其目录结构如下所示 1.1.2 在filter包下创建HTMLFilter类,其内容如下所示 package com.zlz.filter;import javax.servlet.*; import javax.servlet.…