Unity代码热更新和资源热更新
知识点来源:人间自有韬哥在,hybridclr,豆包
目录
- 一、代码热更新
- 1.代码热更新概述
- 2.HybridCLR
- 二、资源热更新
- 1.资源热更新概述
- 2.AB包
- 2.1.AB包的加载
- 2.2.卸载AB包
- 2.3.加载AB包依赖包
- 2.4.获取MD5
- 2.5.生成对比文件
- 2.6.更新AB包
- 3.Addressable
- 3.1.AssetReference资源标识类
- 3.2.加载资源
- 3.3. 异步加载场景
- 3.4.释放资源
- 3.5.通过名字加载资源
- 3.6.通过名字释放资源
- 3.7.通过名字动态加载场景
- 3.8.根据资源名或标签名加载多个对象
- 3.9.根据多种信息加载对象
- 3.10.根据资源定位信息加载资源
- 3.11.AsyncOperationHandle
一、代码热更新
1.代码热更新概述
代码热更新是指在应用程序运行过程中,无需重新启动整个程序,就能对代码进行更新和修改,使新的代码逻辑生效。在游戏开发等领域,这一技术极为关键。例如,当游戏上线后发现严重的代码漏洞或需要快速添加新功能时,代码热更新能让开发者迅速修复问题或推送新内容,避免玩家因重新下载和安装完整游戏而流失。
2.HybridCLR
(1)安装 2019.4.40、2020.3.26+、 2021.3.0+、2022.3.0+ 中任一版本
(2)填入https://gitee.com/focus-creative-games/hybridclr_unity.git或https://github.com/focus-creative-games/hybridclr_unity.git
(3)打开菜单HybridCLR/Installer…, 点击安装按钮进行安装。 耐心等待30s左右,安装完成后会在最后打印 安装成功日志。
(4)创建 Assets/HotUpdate 目录,在目录下 右键 Create/Assembly Definition,创建一个名为HotUpdate的程序集模块
(5)打开菜单 HybridCLR/Settings, 在Hot Update Assemblies配置项中添加HotUpdate程序集
(5)配置PlayerSettings
- 如果你用的hybridclr包低于v4.0.0版本,需要关闭增量式GC(Use Incremental GC) 选项
- Scripting Backend 切换为 IL2CPP
- Api Compatability Level 切换为 .Net 4.x(Unity 2019-2020) 或 .Net Framework(Unity 2021+)
(6)创建热更新脚本, Assets/HotUpdate/Hello.cs
using System.Collections;
using UnityEngine;public class Hello
{public static void Run(){Debug.Log("Hello, HybridCLR");}
}
(7)创建Assets/LoadDll.cs脚本
using HybridCLR;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;public class LoadDll : MonoBehaviour
{void Start(){// Editor环境下,HotUpdate.dll.bytes已经被自动加载,不需要加载,重复加载反而会出问题。
#if !UNITY_EDITORAssembly hotUpdateAss = Assembly.Load(File.ReadAllBytes($"{Application.streamingAssetsPath}/HotUpdate.dll.bytes"));
#else// Editor下无需加载,直接查找获得HotUpdate程序集Assembly hotUpdateAss = System.AppDomain.CurrentDomain.GetAssemblies().First(a => a.GetName().Name == "HotUpdate");
#endifType type = hotUpdateAss.GetType("Hello");type.GetMethod("Run").Invoke(null, null);}}
(8)打包运行
- 运行菜单
HybridCLR/Generate/All
进行必要的生成操作。这一步不可遗漏!!! - 将{proj}/HybridCLRData/HotUpdateDlls/StandaloneWindows64(MacOS下为StandaloneMacXxx)目录下的HotUpdate.dll复制到Assets/StreamingAssets/HotUpdate.dll.bytes,注意,要加.bytes后缀!!!
- 打开Build Settings对话框,点击Build And Run,打包并且运行热更新示例工程。
(9) 测试更新
- 修改Assets/HotUpdate/Hello.cs的Run函数中Debug.Log(“Hello, HybridCLR”);代码,改成Debug.Log(“Hello, World”);。
- 运行菜单命令
HybridCLR/CompileDll/ActiveBulidTarget
重新编译热更新代码。 - 将{proj}/HybridCLRData/HotUpdateDlls/StandaloneWindows64(MacOS下为StandaloneMacXxx)目录下的HotUpdate.dll复制为刚才的打包- 输出目录的 XXX_Data/StreamingAssets/HotUpdate.dll.bytes。
- 重新运行程序,会发现屏幕中显示Hello, World,表示热更新代码生效了!
二、资源热更新
1.资源热更新概述
资源热更新是指在应用程序运行时,对游戏或应用的资源(如图片、音频、视频、模型等)进行更新,而无需重新安装整个应用。这在游戏开发中尤为重要,因为游戏资源通常较大,且随着游戏的运营,需要不断更新资源以提供新的内容和优化体验。例如,一款手机游戏需要定期更新角色皮肤、地图场景、剧情动画等资源,通过资源热更新,玩家无需重新下载整个游戏包,就能获取并使用这些新资源。
2.AB包
2.1.AB包的加载
AB包的同步加载
- 加载AB包:使用
AssetBundle.LoadFromFile
方法可同步地从指定路径加载AB包,并返回加载后的AB包对象。由于通常在StreamingAssets
中会多拷贝一份,所以可以直接从该路径加载。
示例代码:
AssetBundle modelAssetBundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "model");
注意:同一个AB包不能重复加载,否则会报错,如以下代码会引发错误:
//AssetBundle modelAssetBundle2 = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "model");//报错
- 加载AB包中的资源:通过
AssetBundle.LoadAsset
方法,可从一个已加载的AB包中同步加载指定资源。
示例代码:
// 不建议只传名字,因为可能会得到同名不同类型的资源
GameObject cube = modelAssetBundle.LoadAsset("Cube", typeof(GameObject)) as GameObject;
Instantiate(cube);
// 同一个AB包可用于加载多个不同资源
GameObject sphere = modelAssetBundle.LoadAsset<GameObject>("Sphere");
Instantiate(sphere);
AB包的异步加载
- 加载AB包:
AssetBundle.LoadFromFileAsync
方法用于异步地从指定路径加载AB包,返回一个异步加载AB包的类AssetBundleCreateRequest
。 - 加载AB包中的资源:
AssetBundle.LoadAssetAsync
方法可异步地从一个已加载的AB包中加载指定资源。异步加载也有多个重载方法,使用时需注意避免仅传名字的方式(可能得到同名不同类型资源),泛型加载在Lua中不支持,建议传入资源的Type。
示例协程代码:
IEnumerator LoadAssetBundleAsync<T>(string AssetBundleName, string resourceName, Type resourceType)
{// 异步加载AB包AssetBundleCreateRequest assetBundleCreateRequest = AssetBundle.LoadFromFileAsync(Application.streamingAssetsPath + "/" + AssetBundleName);yield return assetBundleCreateRequest;// 异步加载AB包中的资源// 不建议只传名字// AssetBundleRequest assetBundleRequest = assetBundleCreateRequest.assetBundle.LoadAssetAsync(resourceName);AssetBundleRequest assetBundleRequest = assetBundleCreateRequest.assetBundle.LoadAssetAsync(resourceName, resourceType);// 泛型加载在Lua中不支持// AssetBundleRequest assetBundleRequest = assetBundleCreateRequest.assetBundle.LoadAssetAsync<T>(resourceName);yield return assetBundleRequest;// 获取实际加载出的资源并as成实际类型image.sprite = assetBundleRequest.asset as Sprite;
}
- 使用协程进行异步加载:通过
StartCoroutine
开启协程进行异步加载,要确保传入的资源类型正确。
示例代码:
StartCoroutine(LoadAssetBundleAsync<Sprite>("icon", "quanlity_0", typeof(Sprite)));
2.2.卸载AB包
- 卸载指定AB包:
AssetBundle.Unload
方法用于卸载指定的AB包,传入的参数bool
值表示是否卸载场景上加载出来的AB包资源。
示例代码:
modelAssetBundle.Unload(false);
- 卸载所有已加载的AB包:
AssetBundle.UnloadAllAssetBundles
方法可卸载所有已加载的AB包,同样传入的参数bool
值表示是否卸载场景上加载出来的AB包资源。
示例代码:
AssetBundle.UnloadAllAssetBundles(false);
2.3.加载AB包依赖包
//加载主包 主包的名字和AB包生成路径一样
AssetBundle mainAssetBundle = AssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + "PC");//加载AB包依赖关系清单文件
//AssetBundleManifest是Unity中用于管理AB包依赖关系的类。
AssetBundleManifest assetBundleManifest = mainAssetBundle.LoadAsset<AssetBundleManifest>("AssetBundleManifest");//GetAllDependencies方法 传入AB包名得到AB包依赖的所有AB包
string[] modelDependencieAssetBundleNameArray = assetBundleManifest.GetAllDependencies("model");//遍历依赖的所有AB包
for (int i = 0;i< modelDependencieAssetBundleNameArray.Length;i++)
{Debug.Log(modelDependencieAssetBundleNameArray[i]);//iconAssetBundle.LoadFromFile(Application.streamingAssetsPath + "/" + modelDependencieAssetBundleNameArray[i]);//遍历加载所有依赖的AB包
}GameObject cube2 = modelAssetBundle.LoadAsset("Cube", typeof(GameObject)) as GameObject;
Instantiate(cube2);//生成的cube因为加载了所需要的所有依赖包 不会丢失材质
2.4.获取MD5
通过资源名或者资源大小无法判断资源是否更新,因此需要利用MD5的唯一性来判断资源的更新
private string GetMD5(string filePath)
{// 将文件以流的形式打开using (FileStream fileStream = new FileStream(filePath, FileMode.Open)){// 声明一个MD5对象用于生成MD5码MD5 md5 = new MD5CryptoServiceProvider();// 利用ComputeHash方法得到数据的MD5码,返回一个字节数组byte[] md5Info = md5.ComputeHash(fileStream);// 关闭文件流fileStream.Close();// 将字节数组形式的MD5码转换为16进制字符串StringBuilder stringBuilder = new StringBuilder();for (int i = 0; i < md5Info.Length; i++){// 将字节数组中的每个字节转换为两位的16进制字符串,并追加到stringBuilder中 x2代表转成16进制stringBuilder.Append(md5Info[i].ToString("x2"));}// 返回生成的MD5字符串return stringBuilder.ToString();}
}
2.5.生成对比文件
[MenuItem("AB包工具/创建对比文件")]
public static void CreateABCompareFile()
{//获取文件夹信息DirectoryInfo directory = Directory.CreateDirectory(Application.dataPath + "/ArtRes/AB/PC/");//获取该目录下的所有文件信息FileInfo[] fileInfos = directory.GetFiles();//用于存储信息的 字符串string abCompareInfo = "";foreach (FileInfo info in fileInfos){//没有后缀的 才是AB包 我们只想要AB包的信息if(info.Extension == ""){//拼接一个AB包的信息abCompareInfo += info.Name + " " + info.Length + " " + GetMD5(info.FullName);//用一个分隔符分开不同文件之间的信息abCompareInfo += '|';}}//因为循环完毕后 会在最后由一个 | 符号 所以 把它去掉abCompareInfo = abCompareInfo.Substring(0, abCompareInfo.Length - 1);//存储拼接好的 AB包资源信息File.WriteAllText(Application.dataPath + "/ArtRes/AB/PC/ABCompareInfo.txt", abCompareInfo);//刷新编辑器AssetDatabase.Refresh();Debug.Log("AB包对比文件生成成功");
}
2.6.更新AB包
遍历远端 AB 包字典
发现本地 AB 包字典没有对应 AB 包就直接下载
发现本地 AB 包字典有对应 AB 包但是 MD5 码不同就更新
遍历远端 AB 包字典时边遍历边移除本地 AB 包字典可能存在的 AB 包,这样本地 AB 包字典剩下的就是要删除的 AB 包
3.Addressable
3.1.AssetReference资源标识类
AssetReference
:通用资源标识类,可用于加载任意类型资源AssetReferenceAtlasedSprite
:图集资源标识类AssetReferenceGameObject
:游戏对象资源标识类AssetReferenceSprite
:精灵图片资源标识类AssetReferenceTexture
:贴图资源标识类AssetReferenceTexture2D
AssetReferenceTexture3D
AssetReferenceT<T>
:指定类型标识类
通过声明不同类型标识类对象,可在Inspector窗口中筛选关联的资源对象,示例代码:
public AssetReference assetReference;
public AssetReferenceAtlasedSprite assetReferenceAtlasedSprite;
public AssetReferenceGameObject assetReferenceGameObject;
public AssetReferenceSprite assetReferenceSprite;
public AssetReferenceTexture assetReferenceTexture;public AssetReferenceT<AudioClip> assetReferenceTAudioClip;
public AssetReferenceT<RuntimeAnimatorController> assetReferenceTRuntimeAnimatorController;
public AssetReferenceT<TextAsset> assetReferenceTTextAsset;public AssetReferenceT<Material> assetReferenceTMaterial;public AssetReference AssetReferenceScene;
3.2.加载资源
- 注意事项:
- 所有Addressables加载相关都使用异步加载。
- 加载资源时建议选择
Simulate Groups(advanced)
模拟模式,而非Use Existing Build(requires built groups)
(从AB包模式中加载)。
- 相关方法:
AssetReference.LoadAssetAsync
:异步加载可寻址资源,返回异步操作处理者AsyncOperationHandle
对象。AsyncOperationHandle.Completed
:完成回调,添加监听函数进行对完成事件的监听。AsyncOperationHandle.Status
:异步加载状态,一般用于判断是否成功。AsyncOperationHandle.Result
:异步加载出来的资源。AssetReference.IsDone
判断资源是否加载AssetReference.Asset
加载出来的资源
示例代码:
// 异步加载可寻址资源
AsyncOperationHandle<GameObject> asyncOperationHandle = assetReference.LoadAssetAsync<GameObject>();
// 添加完成回调监听
asyncOperationHandle.Completed += OnAsyncOperationHandleCompleted;// 加载成功后的回调函数
private void OnAsyncOperationHandleCompleted(AsyncOperationHandle<GameObject> asyncOperationHandle)
{if (asyncOperationHandle.Status == AsyncOperationStatus.Succeeded){Instantiate(asyncOperationHandle.Result);}// 使用标识类创建// if(assetReference.IsDone)// {// Instantiate(assetReference.Asset);// }
}
3.3. 异步加载场景
使用AssetReference.LoadSceneAsync
异步加载场景,并添加Completed
回调。
AssetReferenceScene.LoadSceneAsync().Completed += (asyncOperationHandle) =>
{print("场景加载结束");
};
3.4.释放资源
- 使用
AssetReference.ReleaseAsset
释放资源,建议在加载成功且用完资源后,在加载成功的回调中释放,避免没加载成功就释放。 - 注意事项:
- 执行释放资源方法后,资源标识类中的资源会置空,但
AsyncOperationHandle
类中的对象不为空。 - 释放资源不会影响场景中已实例化出来的对象,但会影响使用的资源(如AB包模式下赋值材质后释放会丢失材质)。
- 执行释放资源方法后,资源标识类中的资源会置空,但
示例代码:
assetReference.LoadAssetAsync<GameObject>().Completed += (asyncOperationHandle) =>
{if (asyncOperationHandle.Status == AsyncOperationStatus.Succeeded){GameObject cube = Instantiate(asyncOperationHandle.Result);assetReference.ReleaseAsset();assetReferenceTMaterial.LoadAssetAsync().Completed += (materialAsyncOperationHandle) =>{cube.GetComponent<MeshRenderer>().material = materialAsyncOperationHandle.Result;assetReferenceTMaterial.ReleaseAsset();print(materialAsyncOperationHandle.Result);print(assetReferenceTMaterial.Asset);};}
};
接实例化对象
使用AssetReference.InstantiateAsync
异步实例化对象,该方法有一些重载可调整位置角度等,相当于自动完成LoadAssetAsync
并在Completed
回调中实例化对象的操作,一般适用于GameObject预设体。
assetReferenceGameObject.InstantiateAsync();
通过标签相关特性约束标识类对象
意味着assetReference只能关联标签为”SD”, “HD”, “FHD”的资源
[AssetReferenceUILabelRestriction("SD", "HD", "FHD")]
public AssetReference assetReference;
3.5.通过名字加载资源
动态加载单个资源
在Unity中,可使用Addressables
来动态加载单个资源,需引用UnityEngine.AddressableAssets
和UnityEngine.ResourceManagement.AsyncOperations
命名空间。使用Addressables.LoadAssetAsync
方法,传入资源名或标签名来动态加载单个资源。
示例代码
Addressables.LoadAssetAsync<GameObject>("Red").Completed += (asyncOperationHandle) =>
{if (asyncOperationHandle.Status == AsyncOperationStatus.Succeeded)Instantiate(asyncOperationHandle.Result);
};
** 注意事项**
- 重复加载相同资源不会报错,但没有对应的Key会报错。
- 若存在同名或同标签的同类型资源,会自动加载找到的第一个满足条件的对象。
- 若存在同名或同标签的不同类型资源,可根据泛型类型来决定加载哪一个。
3.6.通过名字释放资源
使用Addressables.Release
方法释放资源,要在资源加载完成且使用完毕后进行释放。
asyncOperationHandle = Addressables.LoadAssetAsync<GameObject>("Cube");
asyncOperationHandle.Completed += (handle) =>
{if (handle.Status == AsyncOperationStatus.Succeeded)Instantiate(handle.Result);Addressables.Release(handle);
};// 在对象被删除后释放是较为合理的
private void OnDestroy()
{Addressables.Release(asyncOperationHandle);
}
3.7.通过名字动态加载场景
使用Addressables.LoadSceneAsync
动态加载场景,可手动激活异步加载的场景。
Addressables.LoadSceneAsync("SampleScene", UnityEngine.SceneManagement.LoadSceneMode.Single, false).Completed += (handle) =>
{Debug.Log("异步场景加载完成");handle.Result.ActivateAsync().completed += (a) =>{Debug.Log("异步激活场景完成");Addressables.Release(handle);};
};
3.8.根据资源名或标签名加载多个对象
使用Addressables.LoadAssetsAsync
传入一个Key异步加载多个资源。
// 回调函数处理资源obj
Addressables.LoadAssetsAsync<Object>("Cube", (obj) =>
{print("回调函数处理资源" + obj.name);
});// asyncOperationHandle完成事件中处理资源handle.Result
AsyncOperationHandle<IList<Object>> asyncOperationHandle = Addressables.LoadAssetsAsync<Object>("Red", (obj) =>
{// print(obj.name);
});
asyncOperationHandle.Completed += (handle) =>
{foreach (var item in handle.Result){print("asyncOperationHandle完成时间中处理资源" + item.name);}Addressables.Release(handle);
};
3.9.根据多种信息加载对象
使用Addressables.LoadAssetsAsync
传入Key列表异步加载多个资源,可指定合并模式。
List<string> keyList = new List<string>() { "Cube", "Red" };
Addressables.LoadAssetsAsync<Object>(keyList, (obj) => { print("根据多种信息加载对象" + obj.name); },Addressables.MergeMode.Intersection);
3.10.根据资源定位信息加载资源
根据名字或者标签获取资源定位信息加载资源
可使用Addressables.LoadResourceLocationsAsync
异步加载单Key资源定位信息,再通过Addressables.LoadAssetAsync
传入ResourceLocation
资源定位信息进行资源加载。
示例代码如下:
// 异步加载资源定位信息 返回列表型handle
AsyncOperationHandle<IList<IResourceLocation>> asyncOperationHandle = Addressables.LoadResourceLocationsAsync("Cube", typeof(GameObject));
asyncOperationHandle.Completed += (handle) =>
{if (handle.Status == AsyncOperationStatus.Succeeded){// handle.Result是所有满足条件的资源的资源定位信息列表foreach (var resourceLocation in handle.Result){// 打印出资源名print(resourceLocation.PrimaryKey);// 根据资源定位信息异步加载资源Addressables.LoadAssetAsync<GameObject>(resourceLocation).Completed += (obj) => { Instantiate(obj.Result); };}}else{Addressables.Release(asyncOperationHandle);}
};
根据名字标签组合信息获取资源定位信息加载资源
使用Addressables.LoadResourceLocationsAsync
异步加载多Key资源定位信息,结合资源名和标签名的组合、合并模式以及资源类型进行加载。
示例代码如下:
// 异步加载组合型资源定位信息 返回列表型handle
AsyncOperationHandle<IList<IResourceLocation>> asyncOperationHandle2 = Addressables.LoadResourceLocationsAsync(new List<string>() { "Cube", "Sphere", "SD" }, Addressables.MergeMode.Union, typeof(Object));
asyncOperationHandle2.Completed += (handle) =>
{if (handle.Status == AsyncOperationStatus.Succeeded){// 资源定位信息加载成功foreach (var resourceLocation in handle.Result){// 使用定位信息来加载资源print("******");print(resourceLocation.PrimaryKey); // 资源名print(resourceLocation.InternalId); // 资源路径print(resourceLocation.ResourceType.Name); // 资源类型Addressables.LoadAssetAsync<Object>(resourceLocation).Completed += (obj) =>{// Instantiate(obj.Result);};}}else{Addressables.Release(asyncOperationHandle2);}
};
3.11.AsyncOperationHandle
获取加载进度
通过 AsyncOperationHandle.GetDownloadStatus
可获取下载状态,包含以下属性:
DownloadStatus.Percent
:下载进度DownloadStatus.DownloadedBytes
:当前已下载字节数DownloadStatus.TotalBytes
:总共需下载字节数
示例代码:
IEnumerator LoadAssetCoroutine()
{AsyncOperationHandle<GameObject> asyncOperationHandle = Addressables.LoadAssetAsync<GameObject>("Cube");while (!asyncOperationHandle.IsDone){DownloadStatus downloadStatus = asyncOperationHandle.GetDownloadStatus();print(downloadStatus.Percent);print(downloadStatus.DownloadedBytes + "/" + downloadStatus.TotalBytes);yield return 0;}if (asyncOperationHandle.Status == AsyncOperationStatus.Succeeded){Instantiate(asyncOperationHandle.Result);}elseAddressables.Release(asyncOperationHandle);
}
StartCoroutine(LoadAssetCoroutine());
无类型句柄转换
- 有类型的
AsyncOperationHandle
可隐式转换为无类型的AsyncOperationHandle
。 - 使用
AsyncOperationHandle.Convert<T>()
可将无类型句柄转换为有类型的泛型对象。
示例代码:
AsyncOperationHandle<Texture2D> asyncOperationHandleTexture2D = Addressables.LoadAssetAsync<Texture2D>("Cube");
// 有类型转无类型
AsyncOperationHandle tempAsyncOperationHandle = asyncOperationHandleTexture2D;
// 无类型转有类型
asyncOperationHandleTexture2D = tempAsyncOperationHandle.Convert<Texture2D>();
这种转换便于在 Addressables
管理器字典中使用 AsyncOperationHandle
类型。
强制同步加载资源
使用 AsyncOperationHandle.WaitForCompletion
可等待异步加载完成后继续执行后续代码。
示例代码:
print("1");
asyncOperationHandleTexture2D.WaitForCompletion();
print("2");
print(asyncOperationHandleTexture2D.Result.name);
注意:
- Unity 2020.1 及之前版本,执行该代码会等待所有未完成的异步加载操作完成。
- Unity 2020.2 及之后版本,加载已下载资源时性能影响较小。
总体不建议使用该方式加载资源,因其可能阻塞主线程。
相关文章:
Unity代码热更新和资源热更新
知识点来源:人间自有韬哥在,hybridclr,豆包 目录 一、代码热更新1.代码热更新概述2.HybridCLR 二、资源热更新1.资源热更新概述2.AB包2.1.AB包的加载2.2.卸载AB包2.3.加载AB包依赖包2.4.获取MD52.5.生成对比文件2.6.更新AB包 3.Addressable3.1.AssetRef…...
【MySQL篇】DEPENDENT SUBQUERY(依赖性子查询)优化:从百秒到秒级响应的四种优化办法
💫《博主介绍》:✨又是一天没白过,我是奈斯,从事IT领域✨ 💫《擅长领域》:✌️擅长阿里云AnalyticDB for MySQL(分布式数据仓库)、Oracle、MySQL、Linux、prometheus监控;并对SQLserver、NoSQL(…...
腾讯四面面经
说明 是的,没听错,确实是腾讯四面,而且是技术面。先声明下,这个面经是帮朋友整理的,都是真实的面经,不得不说,四面确实是有强的的,接下来让我们一起看下 面试部门:s3&a…...
【mysql】唯一性约束unique
文章目录 唯一性约束 1. 作用2. 关键字3. 特点4. 添加唯一约束5. 关于复合唯一约束 唯一性约束 1. 作用 用来限制某个字段/某列的值不能重复。 2. 关键字 UNIQUE3. 特点 同一个表可以有多个唯一约束。唯一约束可以是某一个列的值唯一,也可以多个列组合的值唯…...
如何理解前端工程化
前端工程化详解 一、 定义二、特点1. 模块化2. 组件化3. 自动化4. 规范化 三、涉及环节1. 项目架构2. 版本控制:3.自动化构建4.任务自动化5. 部署与CI/CD 五、 前端工程化的实际应用六、前端工程化的优势:七、总结 一、 定义 前端工程化是指将前端开发…...
嵌入式八股RTOS与Linux---进程间的通信与同步篇
前言 同步异步、阻塞/非阻塞是什么? 同步:在执行某个操作时,调用者必须等待该操作完成并返回结果后,才能继续执行后续的操作异步:在执行某个操作时,调用者发起操作后不必等待其完成,可以立即继续执行后续的操作。操作完成后&am…...
this.centerDialogVisible = true this.$nextTick(()=>{ this.resetForm(); })
这段代码的作用是 打开一个对话框,并在对话框打开后 重置表单。下面是对这段代码的详细解析: 1. 代码作用 this.centerDialogVisible true:控制对话框的显示。this.$nextTick(() > { ... }):在 DOM 更新后执行回调函数&#…...
datawhale组队学习--大语言模型—task4:Transformer架构及详细配置
第五章 模型架构 在前述章节中已经对预训练数据的准备流程(第 4 章)进行了介绍。本章主 要讨论大语言模型的模型架构选择,主要围绕 Transformer 模型(第 5.1 节)、详细 配置(第 5.2 节)、主流架…...
专业级 AI 提示生成工具清单
1. 引言 近年来,随着 GPT-3、GPT-4 等大规模预训练语言模型的广泛应用,提示(Prompt)工程作为驱动模型输出质量的重要环节,受到了各界的高度关注。精心设计、管理与优化提示,不仅能够大幅提高生成文本的准确…...
Web前端考核 JavaScript知识点详解
一、JavaScript 基础语法 1.1 变量声明 关键字作用域提升重复声明暂时性死区var函数级✅✅❌let块级❌❌✅const块级❌❌✅ 1.1.1变量提升的例子 在 JavaScript 中,var 声明的变量会存在变量提升的现象,而 let 和 const 则不会。变量提升是指变量的声…...
23种设计模式-生成器(Builder)设计模式
工厂方法设计模式 🚩什么是生成器设计模式?🚩生成器设计模式的特点🚩生成器设计模式的结构🚩生成器设计模式的优缺点🚩生成器设计模式的Java实现🚩代码总结🚩总结 🚩什么…...
Thinkphp(TP)框架漏洞攻略
1.环境搭建 vulhub/thinkphp/5-rce docker-compose up -d 2.访问靶场 远程命令执行: ? sindex/think\app/invokefunction&functioncall_user_func_array&vars[0]system&vars[1] []whoami 远程代码执行: ? s/Index/\think\app/invokefunc…...
HTTP/HTTPS 中 GET 请求和 POST 请求的区别与联系
一、基础概念 HTTP (HyperText Transfer Protocol, 超文本传输协议) 是一种用于浏览器与服务器之间进行数据交互的协议。HTTPS (加密的 HTTP) 则通过 SSL/TLS 协议实现通信加密与数据安全性。 二、GET 和 POST 概述 GET 请求: 用于从服务器获取资源。 POST 请求: 用于将数据…...
2021年蓝桥杯第十二届CC++大学B组真题及代码
目录 1A:空间(填空5分_单位转换) 2B:卡片(填空5分_模拟) 3C:直线(填空10分_数学排序) 4D:货物摆放(填空10分_质因数) 5E…...
解锁 AWX+Ansible 自动化运维新体验:快速部署实战
Ansible 和 AWX 是自动化运维领域的强大工具组合。Ansible 是一个简单高效的 IT 自动化工具,而 AWX 则是 Ansible 的开源 Web 管理平台,提供图形化界面来管理 Ansible 任务。本指南将带你一步步在 Ubuntu 22.04 上安装 Ansible 和 AWX,使用 M…...
简洁、实用、无插件和更安全为特点的WordPress主题
简站WordPress主题是一款以简洁、实用、无插件和更安全为特点的WordPress主题,自2013年创立以来,凭借其设计理念和功能优势,深受用户喜爱。以下是对简站WordPress主题的详细介绍: 1. 设计理念 简站WordPress主题的核心理念是“崇…...
区块链学习总结
Hardhat 是一个用于 Ethereum 智能合约开发 的开发环境,专为 Solidity 语言编写的智能合约提供工具支持。它能够帮助开发者 编译、部署、测试和调试 智能合约,并提供一个本地的以太坊测试网络。 Hardhat 的核心功能 本地开发网络(Hardhat Ne…...
可发1区的超级创新思路(python\matlab实现):基于周期注意力机制的TCN-Informer时间序列预测模型
首先声明,该模型为原创!原创!原创!且该思路还未有成果发表,感兴趣的小伙伴可以借鉴! 一、应用场景 该模型主要用于时间序列数据预测问题,包含功率预测、电池寿命预测、电机故障检测等等 二、模型整体介绍(本文以光伏功率预测为例) 1.1 核心创新点 本模型通过三阶段…...
案例4:鸢尾花分类(pytorch)
一、引言 鸢尾花分类是机器学习领域的经典案例,常用于演示分类算法的基本原理和应用。本案例使用 PyTorch 构建一个简单的神经网络模型,对鸢尾花进行分类。通过该案例,我们可以学习如何使用 PyTorch 进行数据处理、模型构建、训练和评估&…...
本地部署Stable Diffusion生成爆火的AI图片
直接上代码 Mapping("/send") Post public Object send(Body String promptBody) { JSONObject postSend new JSONObject(); System.out.println(promptBody); JSONObject body JSONObject.parseObject(promptBody); List<S…...
CCF-CSP历年真题答案1,2
本文代码主要来自up主圣斗士-DS-ALGO对历年真题的讲解,在此特别感谢。 侵权则删。 10.1_分蛋糕_2017_03 #include <iostream> using namespace std;int main() {int a[1000], n, k; // 定义数组a用于存储蛋糕的重量,整数n表示蛋糕的数量…...
【MySQL】一篇讲懂什么是聚簇索引和非聚簇索引(二级索引)以及什么是回表?
1.聚簇索引: 叶子节点直接存储了完整的数据行。 每个表只能有一个聚簇索引,通常是主键(Primary Key)。如果没有定义主键,则MySQL会选择一个唯一且非空索引作为聚簇索引。 特点: 数据存储:叶子结点存储完整的数据行…...
炫酷的HTML5粒子动画特效实现详解
炫酷的HTML5粒子动画特效实现详解 这里写目录标题 炫酷的HTML5粒子动画特效实现详解项目介绍技术栈项目架构1. HTML结构2. 样式设计 核心实现1. 粒子类设计2. 动画效果实现星空效果烟花效果雨滴效果 3. 鼠标交互 性能优化效果展示总结 项目介绍 本文将详细介绍如何使用HTML5 C…...
go-zero学习笔记
内容不多,只有部分笔记,剩下的没有继续学下去,包括路由与处理器、日志中间件、请求上下文 文章目录 1、go-zero核心库1.1 路由与处理器1.2 日志中间件1.3 请求上下文 1、go-zero核心库 1.1 路由与处理器 package mainimport ("github…...
QuecPython 网络协议之TCP/UDP协议最祥解析
概述 IP 地址与域名 IP 地址是网络中的主机地址,用于两台网络主机能够互相找到彼此,这也是网络通信能够成功进行的基础。IP 地址一般以点分十进制的字符串来表示,如192.168.1.1。 我们日常访问的网站,其所在的服务器主机都有…...
FPGA_YOLO(二)
上述对cnn卷积神经网络进行介绍,接下来对YOLO进行总结,并研究下怎么在FPGA怎么实现的方案。 对于一个7*7*30的输出 拥有49个cell 每一个cell都有两个bbox两个框,并且两个框所包含的信息拥有30个 4个坐标信息和一个置信度5个,剩下就是20个类别。 FPGA关于YOLO的部署 1…...
Camera2 与 CameraX 闲谈
目录 📂 前言 1. 🔱 Camera2 2. 🔱 CameraX 3. 🔱 Camera2 与 CameraX 1)使用复杂度与开发效率 2)控制能力与应用场景 3)设备兼容性与稳定性 4)更新与维护 4. 💠…...
【零基础入门unity游戏开发——2D篇】2D物理系统 —— 2D刚体组件(Rigidbody 2d)
考虑到每个人基础可能不一样,且并不是所有人都有同时做2D、3D开发的需求,所以我把 【零基础入门unity游戏开发】 分为成了C#篇、unity通用篇、unity3D篇、unity2D篇。 【C#篇】:主要讲解C#的基础语法,包括变量、数据类型、运算符、流程控制、面向对象等,适合没有编程基础的…...
【论文#目标检测】YOLO9000: Better, Faster, Stronger
目录 摘要1.引言2.更好(Better)3.更快(Faster)4.更健壮(Stronger)使用 WordTree 组合数据集联合分类和检测评估 YOLO9000 5.结论 Author: Joseph Redmon; Ali Farhadi Published in: 2017 IEEE Conference …...
C++异常处理时的异常类型抛出选择
在 C 中选择抛出哪种异常类型,主要取决于错误的性质以及希望传达的语义信息。以下是一些指导原则,帮助在可能发生异常的地方选择合适的异常类型进行抛出: 1. std::exception 适用场景:作为所有标准异常的基类,std::e…...
centos 7 搭建FTP user-list用户列表
在 CentOS 7 上搭建基于 user_list 的 FTP 用户列表,你可以按以下步骤操作: 1. 安装 vsftpd 服务 若还未安装 vsftpd,可以使用以下命令进行安装: bash yum install -y vsftpd2. 启动并设置开机自启 vsftpd 服务 bash systemctl…...
vulnhub-Tr0ll ssh爆破、wireshark流量分析,exp、寻找flag。思维导图带你清晰拿到所以flag
vulnhub-Tr0ll ssh爆破、wireshark流量分析,exp、寻找flag。思维导图带你清晰拿到所以flag 1、主机发现 arp-scan -l 2、端口扫描 nmap -sS -sV 192.168.66.185 nmap -sS -A -T4 -p- 192.168.66.185 nmap --scriptvuln 192.168.66.185经典扫描三件套,…...
k8s中service概述(二)NodePort
NodePort 是 Kubernetes 中一种用于对外暴露服务的 Service 类型。它通过在集群的每个节点上开放一个静态端口(NodePort),使得外部用户可以通过节点的 IP 地址和该端口访问集群内部的服务。以下是关于 NodePort Service 的详细说明࿱…...
搭建Redis哨兵集群
停掉现有的redis集群 因为这篇文章我是在 搭建完redis主从集群之后写的,如果要是没有搭建过这些,可以直接略过。要是从我上一篇 搭建redis主从集群过来的,可以执行下。 docker compose down 查找下redis相关进程 ps -ef | grep redis 可以看…...
.Net SSO 单点登录方式
SSO单点登录目的 之前一般来讲系统简单,登录后 本地 cookie 加服务器 session 存储用户身份信息,以此为依据来判断用户再次登录时免验证 但随着互联网发展,很多应用 部署在不同的服务器上,而用户体系是一套,那么按照原…...
SQL 基础 BETWEEN 的常见用法
在SQL中,BETWEEN是一个操作符,用于选取介于两个值之间的数据。 它包含这两个边界值。BETWEEN操作符常用于WHERE子句中,以便选取某个范围内的值。 以下是BETWEEN的一些常见用法: 选取介于两个值之间的值: 使用 BETWE…...
ngx_http_add_location
声明在 src\http\ngx_http_core_module.c ngx_int_t ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations,ngx_http_core_loc_conf_t *clcf); 定义在 src\http\ngx_http.c ngx_int_t ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations,ngx_http…...
深入探索ArkUI中的@LocalBuilder装饰器:构建高效可维护的UI组件
在ArkUI框架中,组件化开发是提升代码复用性和维护性的关键手段。随着项目复杂度的增加,开发者常常面临如何在保持组件封装性的同时,灵活处理组件内部逻辑的问题。传统的Builder装饰器虽然提供了强大的自定义构建能力,但在某些场景…...
视频知识库初步设想
将视频字幕提取出来作为知识库来源定位,下一步设想:把视频上的图片信息也精简出来作为定位。 下面是测试例子: 入参: {"model":"deepseek-ai/DeepSeek-R1-Distill-Llama-8B","messages":[{"role":"system","cont…...
微信小程序中使用Less样式方法
在微信小程序中使用Less样式,可以通过以下步骤实现。主要原理是借助Visual Studio Code(VSCode)的插件将Less文件自动编译为小程序支持的.wxss文件,或通过微信开发者工具的扩展功能直接集成Less编译环境。以下是具体方法ÿ…...
2024年MathorCup数学建模A题移动通信网络中PCI规划问题解题全过程文档加程序
2024年第十四届MathorCup高校数学建模挑战赛 A题 移动通信网络中PCI规划问题 原题再现: 物理小区识别码(PCI)规划是移动通信网络中下行链路层上,对各覆盖小区编号进行合理配置,以避免PCI冲突、PCI混淆以及PCI模3干扰等现象。PCI规划对于减少…...
本周安全速报(2025.3.18~3.24)
合规速递 01 2025欧洲网络安全报告:DDoS攻击同比增长137%,企业应如何应对? 原文: https://hackread.com/european-cyber-report-2025-137-more-ddos-attacks/ 最新的Link11《欧洲网络安全报告》揭示了一个令人担忧的趋势:DDo…...
力扣刷题-热题100题-第23题(c++、python)
206. 反转链表 - 力扣(LeetCode)https://leetcode.cn/problems/reverse-linked-list/solutions/551596/fan-zhuan-lian-biao-by-leetcode-solution-d1k2/?envTypestudy-plan-v2&envIdtop-100-liked 常规法 记录前一个指针,当前指针&am…...
YAML是什么?
YAML(YAML Ain’t Markup Language)是一种以数据为中心、高度可读的序列化语言,广泛应用于配置文件、数据交换和自动化工具中。以下从多个维度对其进行全面解析: 1. 定义与历史演变 全称与定位: YAML的全称最初为“Yet…...
期权交易投资怎么操作?新手期权操作指南
期权就是股票,唯一区别标的物上证指数,会看大盘吧,新手做期权交易两个方向认购做多,认沽做空,双向t0交易没了,跟期货一样,对的,玩的也是合约,唯一区别没有保证金不会爆仓…...
音视频学习(三十):fmp4
FMP4(Fragmented MP4)是 MP4(MPEG-4 Part 14)的扩展版本,它支持流式传输,并被广泛应用于DASH(Dynamic Adaptive Streaming over HTTP)和HLS(HTTP Live Streaming…...
破局AI落地困局 亚信科技“四位一体手术刀“切开产业智能三重枷锁
当全球进入以AI为核心竞争力的新经济周期,政企机构的数字化转型正面临关键转折点:IDC数据显示,2023年超过67%的中国企业在AI落地环节遭遇"技术断层",高昂的试错成本与碎片化解决方案让智能转型陷入僵局。在此背景下&…...
android 去掉状态栏的方法汇总
在 Android 开发中,隐藏或去除状态栏(Status Bar)有多种方法,具体实现方式取决于应用场景和目标 Android 版本。以下是常用的 6 种方法及其代码示例: 在 Android 开发中,隐藏或去除状态栏(Sta…...
jenkins+1panel面板java运行环境自动化部署java项目
本文章不包含1panel面板安装、jenkins部署、jenkins连接git服务器等操作教程,如有需要可以抽空后期补上 jenkins安装插件Publish Over SSH 在系统配置添加服务器 查看项目的工作空间 项目Configure->构Post Steps选择Send files or execute commands over SSH…...
VLAN综合实验报告
一、实验拓扑 网络拓扑结构包括三台交换机(LSW1、LSW2、LSW3)、一台路由器(AR1)以及六台PC(PC1-PC6)。交换机之间通过Trunk链路相连,交换机与PC、路由器通过Access或Hybrid链路连接。 二、实验…...