Unity Addressables 使用说明(五)在运行时使用 Addressables(Use Addressables at Runtime)

一旦你将 Addressable assets 组织到 groups 并构建到 AssetBundles 中,就需要在运行时加载、实例化和释放它们。

Addressables 使用引用计数系统来确保 assets 只在需要时保留在内存中。

Addressables 初始化

Addressables 系统在运行时第一次加载 Addressable 或进行其他 Addressable API 调用时会初始化自己。调用 Addressables.InitializeAsync 可以更早地初始化 Addressables。如果已经完成初始化,则此方法不执行任何操作。

初始化任务

初始化操作执行以下任务:

  • 设置[ResourceManager](https://docs.unity3d.com/Packages/com.unity.addressables@2.2/api/UnityEngine.ResourceManagement.ResourceManager.html)[ResourceLocators](https://docs.unity3d.com/Packages/com.unity.addressables@2.2/api/UnityEngine.AddressableAssets.ResourceLocators.html)
  • 加载 Addressables 从StreamingAssets创建的配置数据。
  • 执行任何 initialization object 操作。
  • 加载 content catalog。默认情况下,Addressables 首先检查 content catalog 是否有更新,如果有,则下载新的 catalog。

以下 Addressables 设置可以更改初始化行为:

  • Only update catalogs manually:Addressables 不会自动检查更新的 catalog。有关手动更新 catalogs 的信息,请参见 Updating catalogs。
  • Build Remote Catalog:没有 remote catalog,Addressables 不会尝试加载 remote 内容。
  • Custom certificate handler:如果需要访问 remote asset hosting 服务,请指定一个自定义证书处理程序。
  • Initialization object list:将 [IObjectInitializationDataProvider](https://docs.unity3d.com/Packages/com.unity.addressables@2.2/api/UnityEngine.ResourceManagement.Util.IObjectInitializationDataProvider.html) ScriptableObject 添加到你的应用程序中,Addressables 在初始化操作期间调用它。

在初始化操作开始之前设置以下运行时属性:

  • Custom URL transform function。
  • [ResourceManager exception handler](https://docs.unity3d.com/Packages/com.unity.addressables@2.2/api/UnityEngine.ResourceManagement.ResourceManager.ExceptionHandler.html#UnityEngine_ResourceManagement_ResourceManager_ExceptionHandler)
  • 用于任何 Profile variables 中自定义运行时占位符(placeholders)的静态属性。

Initialization Objects

你可以将对象附加到 Addressable Assets 设置,并在运行时将它们传递到初始化过程中。例如,你可以创建一个 [CacheInitializationSettings](https://docs.unity3d.com/Packages/com.unity.addressables@2.2/api/UnityEditor.AddressableAssets.Settings.CacheInitializationSettings.html) 对象来在运行时初始化 Unity 的 [Cache](https://docs.unity3d.com/2023.1/Documentation/ScriptReference/Cache.html) 设置。

要创建自己的初始化对象类型,请创建一个实现 [IObjectInitializationDataProvider](https://docs.unity3d.com/Packages/com.unity.addressables@2.2/api/UnityEngine.ResourceManagement.Util.IObjectInitializationDataProvider.html) 接口的 ScriptableObject。使用此对象创建 [ObjectInitializationData](https://docs.unity3d.com/Packages/com.unity.addressables@2.2/api/UnityEngine.ResourceManagement.Util.ObjectInitializationData.html) asset,Addressables 在运行时数据中包含它。

Cache Initialization Objects

使用[CacheInitializationSettings](https://docs.unity3d.com/Packages/com.unity.addressables@2.2/api/UnityEditor.AddressableAssets.Settings.CacheInitializationSettings.html)对象在运行时初始化 Unity 的[Cache](https://docs.unity3d.com/2023.1/Documentation/ScriptReference/Cache.html)设置。

要指定 Addressables 系统使用的 cache 初始化设置:

  1. 创建一个 CacheInitializationSettings asset(菜单:Assets > Addressables > Initialization > Cache Initialization Settings)。

  2. 在 Project 面板中选择新 asset 文件以在 Inspector 中查看设置。
    在这里插入图片描述

  3. 根据需要调整设置。

  4. 打开 Addressables 设置 Inspector(菜单:Window > Asset Management > Addressables > Settings)。

  5. 在 Inspector 的 Initialization Objects 部分中,单击 + 按钮将新对象添加到列表中。

  6. 在文件对话框中选择 CacheInitializationSettings asset 并单击 Open

  7. 缓存设置对象已添加到列表中。

当 Addressables 在运行时初始化时,它将这些设置应用于默认的 Unity Cache。设置适用于默认缓存(default cache)中的所有 AssetBundles,而不仅仅是 Addressables 系统下载的那些。有关 Unity cache 系统的更多信息,请参见 Caching 。

内存管理概述

Addressables 系统通过对其加载的每个项进行引用计数来管理加载 assets 和 bundles 所使用的内存。

当 Unity 加载一个 Addressable 时,系统会增加引用计数。当 Unity 释放该 asset 时,系统会减少引用计数。当 Addressable 的引用计数归零时,它可以被卸载。当你显式加载一个 Addressable asset 时,也必须在使用完后释放该 asset

内存泄漏

为了避免内存泄漏,即在不再需要时 assets 仍然保留在内存中,应将每次加载方法的调用与释放方法的调用进行匹配。你可以通过对 asset 实例本身的引用或通过原始加载操作返回的结果 handle 来释放 asset 。

但是,Unity 并不会立即从内存中卸载已释放的 assets ,因为只有当它们所属的 AssetBundle 也被卸载时,内存才会被释放。

AssetBundles 有自己的引用计数,系统将它们视为包含 assets 依赖项的 Addressables。当你从 bundle 加载一个 asset 时,bundle 的引用计数会增加;当你释放该 asset 时,bundle 的引用计数会减少。当 bundle 的引用计数归零时,这意味着 bundle 中包含的所有 assets 都不再使用。此时,Unity 会从内存中卸载该 bundle 及其包含的所有 assets。

使用 Profiler 模块来监控已加载的内容。该模块会显示 assets 及其依赖项何时加载和卸载。

内存清理(Memory Clearance)

如果一个 asset 不再被引用,即 Profiler 模块中显示为已释放状态且文本被禁用,这并不意味着 Unity 已经卸载了该 asset。常见的适用场景包括一个 AssetBundle 中的多个 assets。例如:

  • 你在一个 AssetBundle(stuff)中有三个 assets(tree、tank 和 cow)。
  • 当加载 tree 时,Profiler 显示 tree 和 stuff 各有一个引用计数。
  • 之后,当加载 tank 时,Profiler 显示 tree 和 tank 各有一个引用计数,stuff AssetBundle 有两个引用计数。
  • 如果你释放 tree,它的引用计数变为零,蓝色条消失。

在这个例子中,tree asset 此时并未被卸载。你可以加载一个 AssetBundle 或其部分内容,但不能卸载 AssetBundle 的部分内容。直到整个 AssetBundle 被卸载,stuff 中的 assets 才会被卸载。

避免 asset churn

如果你释放了一个是 AssetBundle 中最后一个项目的对象,并立即重新加载该 asset 或 bundle 中的另一个 asset,则会发生 asset churn。

例如,如果你有两个材质(boat 和 plane)共享一个纹理 cammo,cammo 位于其自己的 AssetBundle 中。Level 1 使用 boat,Level 2 使用 plane。当你退出 Level 1 时,Unity 释放 boat,并立即加载 plane。当 Unity 释放 boat 时,Addressables 会卸载纹理 cammo。然后,当 Unity 加载 plane 时,Addressables 会立即重新加载 cammo。

你可以使用 Profiler 模块帮助检测 asset churn,通过监控 asset 的加载和卸载来实现。

AssetBundle Memory Overhead

当你加载一个 AssetBundle 时,Unity 会分配内存来存储该 bundle 的内部数据以及该 bundle 中包含的 assets。加载的 AssetBundle 的主要内部数据类型包括:

  • 加载缓存:存储最近访问的 AssetBundle 文件页面。使用 [AssetBundle.memoryBudgetKB](https://docs.unity3d.com/2023.1/Documentation/ScriptReference/AssetBundle-memoryBudgetKB.html) 控制其大小。
  • TypeTrees:定义对象的序列化布局。
  • Table of contents:列出 bundle 中的 assets 。
  • Preload table:列出每个 asset 的依赖项。

在组织 Addressable 组和 AssetBundles 时,你需要在创建和加载的 AssetBundles 数量和大小之间进行权衡。较少且较大的 bundles 可以最小化总内存使用量。然而,使用多个小 bundles 可以最小化峰值内存使用量(peak memory usage),因为 Unity 可以更轻松地卸载 assets 和 AssetBundles 。

磁盘上的 AssetBundle 大小与运行时大小并不相同。然而,你可以使用磁盘大小作为构建中 AssetBundles 内存开销的指南。你可以从 Build Layout Report 中获取 bundle 大小和其他信息来帮助分析 AssetBundles。

TypeTrees

TypeTree 描述了项目中数据类型的字段布局(field layout)。

每个序列化文件在 AssetBundle 中都有一个TypeTree,用于文件中的每种对象类型。你可以使用 TypeTree 信息加载与序列化方式略有不同的对象。TypeTree 信息不会在 AssetBundles 之间共享,每个 bundle 都有其包含对象的完整 TypeTrees 集合。

Unity 在加载 AssetBundle 时会加载所有 TypeTrees,并在 AssetBundle 的生命周期内将其保存在内存中。与 TypeTrees 相关的内存开销与序列化文件中唯一类型的数量和这些类型的复杂性成正比。

减少 TypeTree 内存

你可以通过以下方式减少 AssetBundle TypeTrees 的内存需求:

  • 将相同类型的 assets 放在同一个 bundle 中。
  • 禁用 TypeTrees,这会从 bundle 中排除 TypeTree 信息,使 AssetBundles 更小。然而,没有 TypeTree 信息,当你用更新版本的 Unity 加载旧的 bundles 或在项目中进行脚本更改时,可能会出现序列化错误或未定义行为。
  • 使用简单的数据类型来减少 TypeTree 的复杂性。

为了测试 TypeTrees 对 AssetBundles 大小的影响,构建启用和禁用 TypeTrees 的 bundles 并比较它们的大小。使用 BuildAssetBundleOptions.DisableWriteTypeTree 在你的 AssetBundles 中禁用 TypeTrees。

一些平台需要 TypeTrees 并忽略 DisableWriteTypeTree 设置。此外,并非所有平台都支持 TypeTrees。

如果在项目中禁用 TypeTrees,请在构建新的 player 之前始终重新构建本地 Addressable 组。如果你的项目通过远程分发内容,请使用与生成 player 相同版本(包括补丁号)的 Unity 并且不要进行哪怕小的代码更改。如果你使用多个 player 版本、更新和 Unity 版本,禁用 TypeTrees 带来的内存节省可能不值得麻烦。

Table of contents

Table of contents 是 bundle 中的一个 map ,你可以使用它按名称查找每个显式包含的 asset。它的大小与 assets 的数量和字符串名称的长度成线性比例。

Table of contents 数据的大小基于 assets 的总数量。为了最小化用于保存目录数据的内存,请最小化同时加载的 AssetBundles 数量。

预加载表(Preload table)

Preload table 是一个列表,列出了一个 asset 引用的所有其他对象。当你从 AssetBundle 加载一个 asset 时,Unity 使用预加载表来加载这些引用的对象。

例如,一个 prefab 对其每个组件以及它可能引用的任何其他 assets(如材质或纹理)都有一个预加载条目。每个预加载条目为 64 位,可以引用其他 AssetBundles 中的对象。

当一个 asset 引用另一个 asset,而另一个 asset 又引用其他 assets 时,预加载表可能会变大,因为它包含加载这两个 assets 所需的条目。如果两个 assets 都引用第三个 asset,那么两个 assets 的预加载表都包含加载第三个 asset 的条目,无论引用的 asset 是 Addressable 还是在同一个 AssetBundle 中。

例如,一个项目有两个 assets(PrefabA 和 PrefabB)在一个 AssetBundle 中,它们都引用第三个 prefab(PrefabC),PrefabC 很大并且有几个组件和对其他 assets 的引用。这个 AssetBundle 有两个预加载表,一个是 PrefabA 的,一个是 PrefabB 的。这些表包含各自 prefab 的所有对象条目,以及 PrefabC 和 PrefabC 引用的任何对象的条目。加载 PrefabC 所需的信息会在 PrefabA 和 PrefabB 中重复出现。这种情况发生在 PrefabC 是否显式添加到一个 AssetBundle 中。

根据你组织项目中 assets 的方式,AssetBundles 中的预加载表可能会很大并包含许多重复的条目。如果你决定预加载表带来的内存开销是个问题,你可以重新结构化项目中的可加载 assets,使它们具有较少的复杂加载依赖项。

加载 AssetBundle 依赖项

加载一个 Addressable asset 也会加载包含其依赖项的所有 AssetBundles。当一个 bundle 中的 asset 引用另一个 bundle 中的 asset 时,就会发生 AssetBundle 依赖。例如,当一个材质引用一个纹理时。有关更多信息,请参阅 Asset and AssetBundle dependencies 。

Addressables 在 bundle 级别计算 bundle 之间的依赖关系。如果一个 asset 引用另一个 bundle 中的对象,那么整个 bundle 就依赖于那个 bundle。这意味着即使你加载的第一个 bundle 中的 asset 没有自己的依赖项,第二个 AssetBundle 仍会被加载到内存中

例如,BundleA 包含 Addressable assets RootAsset1RootAsset2RootAsset2 引用 DependencyAsset3,它在 BundleB 中。即使 RootAsset1 没有引用 BundleBBundleB 仍然是 RootAsset1 的依赖,因为 RootAsset1BundleA 中,而 BundleA 引用了 BundleB

为了避免加载超过所需数量的 bundles,请尽量简化 AssetBundles 之间的依赖关系。你可以使用 Build Layout Report 检查依赖关系。

管理运行时的 Catalogs

默认情况下,Addressables 系统在运行时自动管理 catalog 。如果你使用了 Remote Catalog 构建应用程序,Addressables 系统会自动检查新目录,下载新版本并加载到内存中。

你可以在运行时加载额外的目录。例如,你可以加载由另一个兼容项目生成的目录,以加载该项目生成的 Addressable 资产。有关更多信息,请参阅 Loading content from multiple 。

如果你想更改 Addressables 系统的默认目录更新行为,可以禁用自动检查,并手动检查更新。有关更多信息,请参阅 Updating catalogs 。

加载额外的目录

使用 Addressables.LoadContentCatalogAsync 加载额外的内容目录,可以从托管服务或本地文件系统加载。你需要提供要加载的目录的位置。目录加载操作完成后,你可以使用新目录中的键调用任何 Addressables 加载函数。

如果你在与目录相同的 URL 上提供目录哈希文件,Addressables 会缓存二级目录。当客户端应用程序加载目录时,只有哈希更改时才会下载新版本的目录。

哈希文件需要与目录位于同一位置并具有相同的名称。路径的唯一区别应该是扩展名。

LoadContentCatalogAsync 带有一个参数 autoReleaseHandle。为了使系统下载新的 Remote Catalog ,指向你要加载的目录的任何先前调用LoadContentCatalogAsync的操作需要被释放。否则,系统会从操作缓存中获取内容目录加载操作。如果从缓存中获取到操作,则不会下载新的 Remote Catalog 。设置autoReleaseHandletrue可以确保操作在完成后不会保留在操作缓存中。

一旦加载目录,就无法卸载它。然而,你可以更新已加载的目录。在更新目录之前,必须释放加载目录的操作句柄。有关更多信息,请参阅 Updating catalogs 。

通常,在加载目录后没有理由保留操作句柄。你可以在加载目录时通过将 autoReleaseHandle 参数设置为 true 来自动释放它,如下例所示:

public IEnumerator Start()
{// 加载目录并自动释放操作句柄。AsyncOperationHandle<IResourceLocator> handle= Addressables.LoadContentCatalogAsync("path_to_secondary_catalog", true);yield return handle;// ...
}

在 Addressables 设置中使用 Catalog Download Timeout 属性指定下载目录的超时时间。

更新目录

如果提供了目录哈希文件,Addressables 会在加载目录时检查哈希,以确定提供的 URL 版本是否比缓存的目录版本更新。你可以禁用默认目录检查,并在需要更新目录时调用 Addressables.UpdateCatalogs 方法。如果你使用 LoadContentCatalogAsync 手动加载目录,则在更新目录之前必须释放操作句柄。

调用 UpdateCatalog 方法时,Unity 会阻止所有其他 Addressable 请求,直到操作完成。你可以在操作完成后立即释放 UpdateCatalog 返回的操作句柄,或者将 autoRelease 参数设置为true

如果在不提供目录列表的情况下调用UpdateCatalog,Addressables 会检查所有已加载的目录是否有更新。

IEnumerator UpdateCatalogs()
{AsyncOperationHandle<List<IResourceLocator>> updateHandle= Addressables.UpdateCatalogs();yield return updateHandle;updateHandle.Release();
}

你也可以直接调用Addressables.CheckForCatalogUpdates获取有更新的目录列表,然后执行更新:

IEnumerator CheckCatalogs()
{List<string> catalogsToUpdate = new List<string>();AsyncOperationHandle<List<string>> checkForUpdateHandle= Addressables.CheckForCatalogUpdates();checkForUpdateHandle.Completed += op => { catalogsToUpdate.AddRange(op.Result); };yield return checkForUpdateHandle;if (catalogsToUpdate.Count > 0){AsyncOperationHandle<List<IResourceLocator>> updateHandle= Addressables.UpdateCatalogs(catalogsToUpdate);yield return updateHandle;updateHandle.Release();}checkForUpdateHandle.Release();
}

运行时获取地址

默认情况下,Addressables 使用你分配给资源的地址作为其[IResourceLocation](https://docs.unity3d.com/Packages/com.unity.addressables@2.2/api/UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation.html)实例的[PrimaryKey](https://docs.unity3d.com/Packages/com.unity.addressables@2.2/api/UnityEngine.ResourceManagement.ResourceLocations.IResourceLocation.PrimaryKey.html#UnityEngine_ResourceManagement_ResourceLocations_IResourceLocation_PrimaryKey)值。

如果禁用了资源所属的 Addressables 组的[Include Addresses in Catalog](https://docs.unity3d.com/Packages/com.unity.addressables@2.2/manual/ContentPackingAndLoadingSchema.html)选项,PrimaryKey 可以是 GUID、Label 或空字符串。如果你想获取使用 AssetReference 或标签加载的资源地址,可以加载资源的位置,如Load assets by location 所述。然后,你可以使用 IResourceLocation 实例来访问 PrimaryKey 值并加载资源。

以下示例获取分配给名为 MyRef1[AssetReference](https://docs.unity3d.com/Packages/com.unity.addressables@2.2/api/UnityEngine.AddressableAssets.AssetReference.html) 对象的资源地址:

var opHandle = Addressables.LoadResourceLocationsAsync(MyRef1);
yield return opHandle;if (opHandle.Status == AsyncOperationStatus.Succeeded &&opHandle.Result != null &&opHandle.Result.Count > 0)
{Debug.Log("address is: " + opHandle.Result[0].PrimaryKey);
}

Labels 通常引用多个资源。以下示例演示了如何加载多个预制件资源并使用其主键值将它们添加到字典中:

Dictionary<string, GameObject> _preloadedObjects= new Dictionary<string, GameObject>();private IEnumerator PreloadHazards()
{// 查找所有带有标签 "SpaceHazards" 的位置var loadResourceLocationsHandle= Addressables.LoadResourceLocationsAsync("SpaceHazards", typeof(GameObject));if (!loadResourceLocationsHandle.IsDone)yield return loadResourceLocationsHandle;// 开始加载每个位置的资源List<AsyncOperationHandle> opList = new List<AsyncOperationHandle>();foreach (IResourceLocation location in loadResourceLocationsHandle.Result){AsyncOperationHandle<GameObject> loadAssetHandle= Addressables.LoadAssetAsync<GameObject>(location);loadAssetHandle.Completed +=obj => { _preloadedObjects.Add(location.PrimaryKey, obj.Result); };opList.Add(loadAssetHandle);}// 创建一个 GroupOperation 一次性等待所有上述加载操作完成var groupOp = Addressables.ResourceManager.CreateGenericGroupOperation(opList);if (!groupOp.IsDone)yield return groupOp;loadResourceLocationsHandle.Release();// 查看我们的结果foreach (var item in _preloadedObjects){Debug.Log(item.Key + " - " + item.Value.name);}
}

此代码段展示了如何加载带有特定标签的资源,并将加载的资源添加到字典中以便后续使用。

修改事件(Modification events)

你可以使用修改事件向 Addressables 系统的某些部分发出信号,当某些数据被操作时,例如添加或移除 AddressableAssetGroupAddressableAssetEntry 时。

修改事件作为 SetDirty 调用的一部分被触发。SetDirty 用于指示需要由 AssetDatabase 重新序列化的资源。作为 SetDirty 的一部分,可以触发两个修改事件回调:

public static event Action<AddressableAssetSettings, ModificationEvent, object> OnModificationGlobal
public Action<AddressableAssetSettings, ModificationEvent, object> OnModification { get; set; }

这些回调分别通过静态或实例访问器在[AddressableAssetSettings](https://docs.unity3d.com/Packages/com.unity.addressables@2.2/api/UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.html)中找到。

修改事件示例

AddressableAssetSettings.OnModificationGlobal += (settings, modificationEvent, data) =>
{if(modificationEvent == AddressableAssetSettings.ModificationEvent.EntryAdded){// 执行工作}
};
AddressableAssetSettingsDefaultObject.Settings.OnModification += (settings, modificationEvent, data) =>
{if (modificationEvent == AddressableAssetSettings.ModificationEvent.EntryAdded){// 执行工作}
};

修改事件传递一个通用对象,用于与事件关联的数据。下表列出了修改事件及其传递的数据类型。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PLSQL-将一份excel数据导入到一张物理表(Oracle)

–>> 很简单~ 平时用惯了DBeaver&#xff0c;突然要用PLSQL Developer&#xff0c;确实很生疏。 –>> 我的场景&#xff0c;将一份.csv文件数据手动导入到Oracle下的一张物理表中去。 研究了半天&#xff0c;看网上说的可以用&#xff1a;Tools → ODBC Importer &…

视频监控接入平台web客户端有时无法登录,有时打开实时视频出现黑屏的问题解决

目录 一、背景说明 二、解决过程 1、问题产生 2、命令介绍 ①基本用法 ②常用选项 ③示例 3、问题解决 三、最终结果 一、背景说明 在本地登录视频监控平台的服务器进行测试时&#xff0c;发现客户端登录不上。 检查服务器的服务和数据库&#xff0c;运行状况正常&#xff0c…

opencv 实现两个图片的拼接去重功能

基础知识介绍 cv::Mat 是OpenCV库中用来表示图像和矩阵数据的核心类之一。它是一个多维数组&#xff0c;可以存储图像像素数据、矩阵数据以及其他类型的数据。以下是关于 cv::Mat 类的一些详细解释&#xff1a; 构造函数&#xff1a;cv::Mat 类有多个构造函数&#xff0c;可以用…

【Linux】常用的命令

文章目录 lsls -l / touchcdpwdcatechovim打开文件编辑内容保存退出 mkdirrmmvcpmangreppsnetstat总结 &#xff1a; ls ls > list 列出当前目录下都有哪些内容&#xff08;文件/目录&#xff09; 直接输入 ls&#xff0c;是查看当前目录的情况&#xff1b;输入 ls/ 就是看…

数据结构 --- 二叉树

一、满二叉树 在一棵二叉树中&#xff0c;如果所有分支节点都存在左子树和右子树&#xff0c;并且所有叶子节点都在同一层上&#xff0c;这 样的二叉树称为满二叉树。 每层节点数量为 2 ^ (n - 1) &#xff08;n为层数&#xff09; 总节点个数为 2 ^ n - 1 二、完全…

【Java】基于JWT+Token实现完整登入功能(原理+实操图解)

Java系列文章目录 补充内容 Windows通过SSH连接Linux 第一章 Linux基本命令的学习与Linux历史 文章目录 Java系列文章目录一、前言二、学习内容&#xff1a;三、问题描述四、解决方案&#xff1a;4.1 认识相关依赖4.1.1 工具包依赖4.1.2 非空注解依赖4.1.3 Token相关依赖4.1.4…

【正式版】深度技术Win10系统22H2最新版本:免费下载!

今日&#xff0c;系统之家小编给大家分享2024年最新发布的深度技术Win10正式版系统&#xff0c;该版本系统基于微软官方最新Windows10 22H2 19045.4842 64位专业版进行离线制作&#xff0c;确保安全无病毒&#xff0c;且修复了部分系统Bug&#xff0c;整体操作体验感更出色。系…

6.1排序——插入排序与希尔排序

本篇博客来梳理两种常见排序算法&#xff1a;插入排序与希尔排序 常见的排序算法如图 写排序算法的原则&#xff1a;先写单趟&#xff0c;再写整体 一、直接插入排序 1&#xff0e;算法思想 先假定第一个数据有序&#xff0c;把第二个数据插入&#xff1b;再假设前两个数据…

[【人工智能学习笔记】4_3 深度学习基础之卷积神经网络

卷积神经网络概述 卷积神经网络(Convolutional Neural Network, CNN)一种带有卷积结构的深度神经网络,通过特征提取和分类识别完成对输入数据的判别;在1989年提出,早期被成功用于手写字符图像识别;2012年更深层次的AlexNet网络取得成功,伺候卷积神经网络被广泛应用于各…

uniapp使用uni-popup做底部弹出选项(vue3)

效果图 页面代码 <!-- 发票筛选弹出框 --><uni-popup ref"popupRef" type"bottom" border-radius"10px 10px 0 0" background-color"#fff"><h4 style"text-align: center;margin-bottom: 20px;">发票筛…

node解析dxf文件

1、dxf数据说明 DXF是一种开放的矢量数据格式&#xff0c;可以分为两类&#xff1a;ASCII格式和二进制格式&#xff1b;ASCII具有可读性好的特点&#xff0c;但占用的空间较大&#xff1b;二进制格式则占用的空间小、读取速度快。由于AutoCAD是最流行的CAD系统&#xff0c;DXF也…

uniapp 懒加载、预加载、缓存机制深度解析

uniapp 懒加载、预加载、缓存机制深度解析 文章目录 uniapp 懒加载、预加载、缓存机制深度解析一、为什么要使用uniapp的懒加载、预加载和缓存机制二、如何使用uniapp的懒加载、预加载和缓存机制1. 懒加载2. 预加载3. 缓存机制 四、扩展与高级技巧1. 结合懒加载和预加载优化页面…

眼科市场格局固化,排名靠后的光正眼科还能逆袭吗?

眼科是A股的热门领域&#xff0c;也是医疗的黄金赛道。或许也正因为如此&#xff0c;这条赛道已经习惯了通过并购&#xff0c;利用资本杠杆跑马圈地。以最大规模的龙头爱尔眼科为首&#xff0c;并购是眼科的常规操作。 然而&#xff0c;真正观察赛道腰部及以下的公司&#xff…

elementUI根据列表id进行列合并@莫成尘

本文章提供了elementUI根据列表id进行列合并的demo&#xff0c;效果如图&#xff08;可直接复制代码粘贴&#xff09; <template><div id"app"><el-table border :data"tableList" style"width: 100%" :span-method"objectS…

2024.9.9营养小题【2】

营养&#xff1a; 1、什么数是丑数&#xff1f; 2、数学数学&#xff0c;丑数的数学意义&#xff0c;哎&#xff0c;数学思维我是忘干净了。 3、可以把while循环换成for循环。由此又想到了一点&#xff0c;三个循环结构各有使用场景。 for(;n%factors[i]0;n/factors[i]){}

网络编程day02(字节序、TCP编程)

目录 【1】字节序 1》大小端转换 2》端口转换 3》IP地址转换 主机字节序转换为网络字节序 &#xff08;小端序->大端序&#xff09; 网络字节序转换为主机字节序&#xff08;大端序->小端序&#xff09; 【2】TCP编程 1》流程 2》函数接口 1> socket 2> …

C# 删除Word文档中的段落

在编辑Word文档时&#xff0c;我们有时需要调整段落的布局、删除不必要的段落以优化文档的结构和阅读体验。本文将通过以下3个简单示例演示如何使用免费.NET库删除Word文档中的段落 。 目录 C# 删除Word中的指定段落 C# 删除Word中的所有段落 C# 删除Word中的空白段落 免费…

分组注解和自定义注解及分页查询

自定义注解的使用步骤 案例&#xff1a; 此时state需要进行的校验使用普通方式无法满足&#xff0c;需要我们根据需求进行自定义注解 创建一个注解 Documented//元注解 Retention(RetentionPolicy.RUNTIME)//元注解 Constraint(validatedBy {StateValidation.class}//指定提供…

网络编程day04(UDP、Linux IO 模型)

目录 【1】UDP 1》通信流程 2》函数接口 1> recvfrom 2> sendto 3》代码展示 1> 服务器代码 2> 客户端代码 【2】Linux IO 模型 场景假设一 1》阻塞式IO&#xff1a;最常见、效率低、不耗费CPU 2》 非阻塞 IO&#xff1a;轮询、耗费CPU&#xff0c;可以处…

Java后台生成二维码

一、效果图 二、实现代码 1.添加依赖 <!-- zxing生成二维码 --> <dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.3.3</version> </dependency><dependency><grou…