当前位置: 首页 > news >正文

Unity Adressables 使用说明(五)在运行时使用 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){// 执行工作}
};

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

相关文章:

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

一旦你将 Addressable assets 组织到 groups 并构建到 AssetBundles 中&#xff0c;就需要在运行时加载、实例化和释放它们。 Addressables 使用引用计数系统来确保 assets 只在需要时保留在内存中。 Addressables 初始化 Addressables 系统在运行时第一次加载 Addressable …...

什么是死锁,如何解决?

什么是死锁&#xff1f; 在并发编程中&#xff0c;死锁是指两个或多个进程在竞争资源时&#xff0c;互相等待无法继续执行的状态。这种情况发生时&#xff0c;每个进程都在等待其他进程释放它们所需要的资源&#xff0c;但同时又不释放自己占有的资源&#xff0c;导致所有进程…...

借助ChatGPT三步,完成课题申报书中研究价值部分写作全攻略指南

大家好,感谢关注。我是七哥,一个在高校里不务正业,折腾学术科研AI实操的学术人。关于使用ChatGPT等AI学术科研的相关问题可以和作者七哥(yida985)交流,多多交流,相互成就,共同进步,为大家带来最酷最有效的智能AI学术科研写作攻略。 撰写申请书中的“本课题的学术价值…...

IDEA取消自动选择光标所在行

今天出现了一个怪事&#xff1a; 当我使用IDEA编写代码的时候&#xff0c;单击下一行或者上一行的时候&#xff0c;莫名其妙它会自己选中一行&#xff0c;导致我要么是回车代码直接没了&#xff0c;要么是代码直接给我搞错位了&#xff0c;还得按ctrlz返回&#xff0c;十分的恶…...

VUE2.0 elementUI el-input-number 数据更新,视图不更新——基础积累

今天遇到一个问题&#xff0c;是关于el-input-number组件的&#xff0c;发现数据明明已经更改了&#xff0c;但是页面上组件输入框中还是之前的值。 比如上方输入框中&#xff0c;我输入120.5&#xff0c;就会出现下面的诡异现象 回显此值是120.779&#xff0c;但是页面上输入…...

JS中this指向问题

首先&#xff0c;this的绑定和定义的位置无关&#xff0c;它的指向只和调用方式有关&#xff0c;this只有在运行时才知道指向谁。 一&#xff0c;默认绑定 默认绑定&#xff0c;也可以说是独立函数调用&#xff0c;这时this指向window。 function foo() {console.log(this) …...

大厂面试:小米嵌入式面试题大全及参考答案(130+道 12万长文)

Flink 架构介绍 Flink 是一个分布式流处理和批处理框架,具有高吞吐、低延迟、高可靠等特点。其架构主要由以下几个部分组成: 客户端(Client):负责将作业提交到集群,并与作业管理器进行交互,获取作业的状态信息。客户端可以是命令行工具、IDE 插件或者自定义的应用程序。…...

React 更新界面

文章目录 发现宝藏引入 useState声明和使用状态多个组件的状态管理解析代码 状态的局部性和性能优化结论 发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【宝藏入口】。 在 React 中&#xff…...

JavaSE-易错题集-001

1. AccessViolationException异常触发后&#xff0c;下列程序的输出结果为&#xff08; &#xff09; 1 2 3 4 5 6 7 8 9 10 11 12 13 static void Main(string[] args) { try { throw new AccessViolationException(); Console.Write…...

【人工智能学习笔记】1_人工智能基础

本系列是个人学习《阿里云人工智能工程师ACA认证免费课程&#xff08;2023版&#xff09;》的笔记&#xff0c;仅为个人学习记录&#xff0c;欢迎交流&#xff0c;感谢批评指正 人工智能概述 智能的三大能力&#xff1a;感知、记忆与思维、学习与适应能力人工智能的定义 明斯基…...

【前端】animation动画以及利用vue制作简单的透明度改变动画,包含vue生命周期实现

一. 问题描述 想做一个文字透明度从1到0然后再从0到1的css动画。 二. 代码写法 2.1 animation写法 2.1.1 animation属性key 2.1.2 代码展示 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"…...

mysql优化案例分享

一、mysql介绍 1、InnoDB引擎 mysql5.5.8版本开始后。InnoDB引擎就是默认存储引擎&#xff0c;本文介绍知识点也都是围绕该引擎展开。 知识点1聚集存储 InnoDB引擎采用聚集存储&#xff0c;即每张表的存储都是主键的顺序进行存放&#xff0c;也就是每行存储的物理顺序和主键…...

C语言中结构体struct和联合体union的区别

C语言 文章目录 C语言前言一、什么是结构体二、什么是联合体三、结构体和联合体的区别 前言 一、什么是结构体 在C语言中&#xff0c;结构体指的是一种数据结构&#xff0c;是C语言中聚合数据类型的一类。结构体可以被声明为变量、指针或数组等&#xff0c;用以实现较复杂的数…...

Verilog:【8】基于FPGA实现SD NAND FLASH的SPI协议读写

Verilog&#xff1a;【8】基于FPGA实现SD NAND FLASH的SPI协议读写 在此介绍的是使用FPGA实现SD NAND FLASH的读写操作&#xff0c;以雷龙发展提供的CS创世SD NAND FLASH样品为例&#xff0c;分别讲解电路连接、读写时序与仿真和实验结果。 目录 1 FLASH背景介绍 2 样品申请 3…...

目标检测-RT-DETR

RT-DETR (Real-Time Detection Transformer) 是一种结合了 Transformer 和实时目标检测的创新模型架构。它旨在解决现有目标检测模型在速度和精度之间的权衡问题&#xff0c;通过引入高效的 Transformer 模块和优化的检测头&#xff0c;提升了模型的实时性和准确性。RT-DETR 可…...

业务资源管理模式语言09

示例&#xff1a; 图13 表示了QuoteTheMaintenance 模式的一个实例&#xff0c;在汽车修理店系统中&#xff0c;其中“Vehicle”扮演“Resource”&#xff0c;“Repair Quotation”扮演“Maintenance Quotation”&#xff0c;“Repair shop branch”扮演“Source-party”&…...

Spring Boot + Vue 多级目录的构建详解

1. 背景介绍 1.1 为何选择 Spring Boot Vue&#xff1f; 在现代 Web 开发中&#xff0c;前后端分离已成为一种标准实践。Spring Boot 提供了强大的后端开发能力&#xff0c;尤其在构建企业级应用时&#xff0c;其轻量级、高效性和丰富的生态系统让开发者如虎添翼。而 Vue.js…...

Android的Launch

看了一下资料&#xff0c;其实差别并不像一般的bootloader之类那么大。基本上还是和普通的APK程序差不多&#xff0c;基本上是AMS启动的第一个带界面的程序&#xff0c;这个界面也是常规的开发模式。可以设置各种view&#xff0c;可以设置背景。 然后在这个程序中&#xff0c;…...

Deep Ocr

1.圈出内容,文本那里要有内容.然后你保存,并导出数据集. 2.找出deep_ocr_recognition_training_workflow.hdev 文件.修改“DatasetFilename : Test.hdict” 310行 write_deep_ocr (DeepOcrHandle, BestModelDeepOCRFilename) 3.推理test.hdev 但发现很慢&#xff0c;没有mlp…...

图片验证码

导入依赖 <dependencies><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.25</version></dependency> </dependencies> 代码 Service public class ValidateCodeServi…...

004: VTK读入数据---vtkImageData详细说明

VTK医学图像处理---vtkImageData类 目录 VTK医学图像处理---vtkImageData类 简介&#xff1a; 1 Mricro软件的安装和使用 (1) Mricro安装 (2) Mricro转换DICOM为裸数据 2 从硬盘读取数据到vtkImageData 3 vtkImageData转RGB或RGBA格式 4 练习 总结 简介&#xff1a;…...

分割千万级,将大文件分割为小件 csv

依赖 <dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.9.0</version></dependency> package com.topnet.controller;import com.topnet.utils.R; import lombok.extern.slf4j.Slf4…...

SQL COUNT() 函数深入解析

SQL COUNT() 函数深入解析 SQL&#xff08;Structured Query Language&#xff09;是一种用于管理关系数据库管理系统&#xff08;RDBMS&#xff09;的标准编程语言。在SQL中&#xff0c;COUNT() 函数是一个常用的聚合函数&#xff0c;用于计算数据表中的行数或特定列的值数量…...

vue3和vue2的双向绑定原理

Vue 的双向绑定是其核心特性之一&#xff0c;允许数据和视图之间保持同步。在 Vue 2 和 Vue 3 中&#xff0c;双向绑定的实现原理有所不同。以下是两者的原理对比&#xff1a; Vue 2 的双向绑定原理 在 Vue 2 中&#xff0c;双向绑定是通过以下机制实现的&#xff1a; 响应式…...

[C++]刷题

作者主页&#xff1a; 作者主页 本篇博客专栏&#xff1a;C 创作时间 &#xff1a;2024年6月20日 最后&#xff1a; 十分感谢你可以耐着性子把它读完和我可以坚持写到这里&#xff0c;送几句话&#xff0c;对你&#xff0c;也对我&#xff1a; 1.一个冷知识&#xff1a; …...

职称评审中,论文发表要求?

无论是医生、教师或其他等职业&#xff0c;职称评审无疑是一个非常重要的环节。而职称评审中的论文发表则是评定我们专业能力的重要一环&#xff0c;可如何才能让自己辛苦撰写的的论文被发表&#xff0c;达到论文发表都有哪些要求呢&#xff1f; 一、选题要新颖 编辑和审稿人…...

连续信号的matlab表示

复习信号与系统以及matlab 在matlab中连续信号使用较小的采样间隔来表四 1.单位阶跃信号 阶跃信号:一个理想的单位阶跃信号在时间 t 0 之前值为0&#xff0c;在 t 0 及之后值突然变为常数 A&#xff08;通常取 A 1&#xff09; %matlab表示连续信号,是让信号的采样间隔很小…...

centos7.9搭建mysql5.6主从

mysql5.6 搭建数据库配置主从 搭建数据库 官网下载软件包后上传 基于centos7.9搭建mysql5.6.42 [rootmysql02 ~]# ls anaconda-ks.cfg init.sh MySQL-5.6.42-1.el7.x86_64.rpm-bundle.tar解压 tar -xf MySQL-5.6.42-1.el7.x86_64.rpm-bundle.tar -C /opt/[rootmysql02 ~]…...

C#通过ACE OLEDB驱动程序访问 Access和 Excel

ACE 代表 Access Connectivity Engine。它是 Microsoft 提供的一组组件&#xff0c;用于访问和操作 Microsoft Access 数据库以及其他类似的文件格式&#xff0c;如 Excel 工作簿。ACE 主要包括以下几部分&#xff1a; ACE OLEDB 驱动程序&#xff1a;用于通过 OLE DB 提供程序…...

智能新纪元:GPT-Next引领的AI革命及其跨领域应用

GPT-Next&#xff1a;性能的百倍提升 在当今这个科技日新月异的时代&#xff0c;人工智能&#xff08;AI&#xff09;无疑是最具活力和变革性的领域之一。最近&#xff0c;OpenAI在KDDI峰会上宣布了一项激动人心的消息&#xff1a;他们即将推出名为“GPT-Next”的新一代语言模…...