Unity_Addressable_Operations(运行操作)
Many tasks in the Addressables need to load or download information before they can return a result. To avoid blocking program execution, Addressables implements such tasks as asynchronous operations.
译:Addressables中有许多任务需要在返回结果之前加载或下载信息。为了避免阻塞程序执行,Addressables将这些任务实现为异步操作
In contrast to a synchronous operation, which doesn’t return control until the result is available, an asynchronous operation returns control to the calling function almost immediately. However, the results may not be available until some time in the future. When you call a function, such as LoadAssetAsync, it doesn't return the loaded assets directly. Instead, it returns an AsyncOperationHandle object, which you can use to access the loaded assets when they become available.
译:与同步操作不同的是,异步操作几乎立即将控制权返回给调用函数,但是结果可能要在未来的某个时间才能获得。当调用函数(例如LoadAssetAsync)时,它不会直接返回加载的资产,而是返回一个AsyncOperationHandle对象,当资产可用时,
You can use the following techniques to wait for the results of an asynchronous operation (while allowing other scripts to continue processing).
译:您可以使用该对象访问它们。您可以使用以下技术等待异步操作的结果(同时允许其他脚本继续处理)
Coroutines and IEnumerator loops 协程和IEnumerator循环
Events 事件
Tasks 任务
NOTE
You can block the current thread to wait for the completion of an asynchronous operation. Doing so can introduce performance problems and frame rate hitches. See Using operations synchronously.
译:你可以阻塞当前线程以等待异步操作的完成。这样做可能会引入性能问题和帧速率卡顿。请参阅使用同步操作
Releasing AsyncOperationHandle instances
Methods, like LoadAssetsAsync, return AsyncOperationHandle instances that both provide the results of the operation and a way to release both the results and the operation object itself. You must retain the handle object for as long as you want to use the results. Depending on the situation, that might be one frame, until the end of a level, or even the lifetime of the application. Use the Addressables.Release function to release operation handles and any associated addressable assets.
译:像 LoadAssetsAsync 这样的方法返回 AsyncOperationHandle 实例,它们提供操作的结果以及释放结果和操作对象本身的方式。只要你想使用结果,就必须保留处理对象。根据情况,可能是一帧、直到关卡结束,甚至是应用程序的生命周期。使用 Addressables.Release 函数释放操作句柄和任何相关的可寻址资源。
Releasing an operation handle decrements the reference count of any assets loaded by the operation and invalidates the operation handle object itself. See Memory management for more information about reference counting in the Addressables system.
译:释放操作句柄会减少操作加载的任何资源的引用计数,并使操作句柄对象本身无效。有关 Addressables 系统中引用计数的更多信息,请参阅内存管理。
In cases where you don’t need to use the results of an operation beyond a limited scope, you can release the handles right away. A few Addressables methods, such as UnloadSceneAsync allow you to automatically release the operation handle when it's complete.
译:在某些情况下,如果不需要在受限范围之外使用操作结果,可以立即释放句柄。一些 Addressables 方法,例如 UnloadSceneAsync,允许你在完成时自动释放操作句柄。如果操作失败,你仍然应该释放操作句柄。
If an operation is unsuccessful, you should still release the operation handle. Normally, Addressables releases any assets that it loaded during a failed operation, but releasing the handle still clears the handle’s instance data. Note that some functions, like LoadAssetsAsync, which load multiple assets, give you the option to either retain any assets that it could load or to fail and release everything if any part of the load operation failed.
译:在某些情况下,如果不需要在受限范围之外使用操作结果,可以立即释放句柄。一些 Addressables 方法,例如 UnloadSceneAsync,允许你在完成时自动释放操作句柄。如果操作失败,你仍然应该释放操作句柄。通常,Addressables 在操作失败时会释放它加载的任何资源,但释放句柄仍会清除句柄的实例数据。请注意,一些函数(如 LoadAssetsAsync)允许你选择保留它可以加载的任何资源或在加载操作的任何部分失败时失败并释放所有内容。基于协程和 IEnumerator 的操作处理。AsyncOperationHandle 实现 IEnumerator 接口,并将继续迭代,直到操作完成。
Coroutine- and IEnumerator-based operation handling
The AsyncOperationHandle implements the IEnumerator interface and will continue iteration until the operation is complete. In a coroutine, you can yield the operation handle to wait for the next iteration. When complete, the execution flow continues to the following statements. Recall that you can implement the MonoBehaviour Start function as a coroutine, which is a good way to have a GameObject load and instantiate the assets it needs.
译:在协程中,你可以使用 yield 关键字来等待操作处理,等待结束后,执行流程继续执行以下语句。请记住,你可以将 MonoBehaviour 的 Start 函数实现为协程,这是一个很好的方式,可以让 GameObject 加载并实例化它所需的资产。
The following script loads a Prefab as a child of its GameObject using a Start function coroutine. It yields the AsyncOperationHandle until the operation finishes and then uses the same handle to instantiate the Prefab.
译:下面的脚本使用 Start 函数协程将 Prefab 作为其 GameObject 的子对象进行加载,并在操作完成后使用相同的句柄来实例化 Prefab
Note that Addressables.LoadAssetsAsync is not able to be canceled once started. However, releasing the handle before it has finished will decrement the handle reference count and it will automatically release when the load is complete.
译:请注意,Addressables.LoadAssetsAsync一旦启动就无法取消。但是,在它完成之前释放句柄会递减句柄引用计数,并在加载完成时自动释放
See Coroutines for more information.
译:有关详细信息,请参阅协程
Grouping operations in a coroutine
You will probably encounter situations in which you want to perform several operations before moving on to the next step in your game logic. For example, you want to load a number of Prefabs and other assets before you start a level.
译:您可能会遇到这样的情况,在进行游戏逻辑的下一步之前,您希望执行多个操作。例如,您希望在开始关卡之前加载多个Prefab和其他资产
If the operations all load assets, you can combine them with a single call to the Addressables.LoadAssetsAsync function. The AsyncOperationhandle for this method works the same as LoadAssetAsync; you can yield the handle in a coroutine to wait until all the assets in the operation load. In addition, you can pass a callback function to LoadAssetsAsync and the operation calls that function when it finishes loading a specific asset. See Loading multiple assets for an example.
译:如果这些操作都是加载资产,您可以使用单个调用Addressables.LoadAssetsAsync函数将它们组合在一起。该方法的AsyncOperationhandle与LoadAssetAsync相同;您可以在协程中yield该句柄,以等待操作中所有资产的加载。此外,您可以将回调函数传递给LoadAssetsAsync,当操作完成加载特定资产时,操作会调用该函数。请参阅加载多个资产以获得示例
Another option is to use the ResourceManager.CreateGenericGroupOperation to create a group operation that completes when all of its members finish.
译:另一个选项是使用ResourceManager.CreateGenericGroupOperation创建一个组操作,当其所有成员完成时,该操作将完成
Event-based operation handling
You can add a delegate function to the Completed event of an AsyncOperationHandle. The operation calls the delegate function when it's finished.
译:您可以将委托函数添加到AsyncOperationHandle的Completed事件中。当操作完成时,操作会调用委托函数
The following script performs the same function as the example in Coroutine- and IEnumerator-based operation handling, but uses an event delegate instead of a coroutine.
译:以下脚本执行与Coroutine- and IEnumerator-based操作处理示例相同的功能,但使用事件委托而不是协程
Note that the handle instance passed to the event delegate is the same as that returned by the original function call. You can use either to access the results and status of the operation and, ultimately, to release the operation handle and loaded assets.
译:传递给事件委托的句柄实例与原始函数调用返回的句柄相同。你可以使用任一句柄来访问操作的结果和状态,最终释放操作句柄和已加载的资产
Task-based operation handling
The AsyncOperationHandle provides a Task object that you can use with the C# async and await keywords to sequence code that calls asynchronous functions and handles the results.
译:使用基于任务的操作处理时,AsyncOperationHandle 提供了一个 Task 对象,你可以在调用异步函数并处理结果的代码中使用 C# 的 async 和 await 关键字来进行序列化
The following example loads Addressable assets using a list of keys. The differences between this task-based approach and the coroutine or event-based approaches are in the signature of the calling function, which must include the async keyword and the use of the await keyword with the operation handle’s Task property. The calling function, Start() in this case, suspends operation while the task finishes. Execution then resumes and the example instantiates all the loaded Prefabs (in a grid pattern).
译:下面的示例使用键列表加载 Addressable 资产。这种基于任务的方法与协程或事件驱动方法的区别在于调用函数的签名,必须包括 async 关键字,并使用 await 关键字与操作句柄的 Task 属性。在这种情况下,调用函数 Start() 暂停操作,直到任务完成。然后,示例根据网格模式实例化所有已加载的 Prefab
IMPORTANT
The AsyncOperationHandle.Task property is not available on the Unity WebGL platform, which doesn't support multitasking.
译:Unity WebGL 平台不支持多任务,因此 AsyncOperationHandle.Task 属性在该平台上不可用
When you use Task-based operation handling, you can use the C# Task class methods such as WhenAll to control which operations you run in parallel and which you want to run in sequence. The following example illustrates how to wait for more than one operation to finish before moving onto the next task:
译:当你使用基于任务的操作处理时,可以使用 C# 的 Task 类方法(例如 WhenAll)来控制并行运行的操作和需要按顺序运行的操作。以下示例说明了如何在移动到下一个任务之前等待多个操作完成
Using operations synchronously
You can wait for an operation to finish without yielding, waiting for an event, or using async await
by calling an operation’s WaitForCompletion method. This method blocks the current program execution thread while it waits for the operation to finish before continuing in the current scope.
译:通过调用操作的 WaitForCompletion 方法,您可以在不使用 yield、等待事件或使用 async await 的情况下等待操作完成。该方法会阻塞当前程序执行线程,直到操作完成后才在当前作用域中继续执行
Avoid calling WaitForCompletion on operations that can take a significant amount of time, such as those that must download data. Calling WaitForCompletion can cause frame hitches and interrupt UI responsiveness.
译:避免在需要下载数据的操作上调用 WaitForCompletion,因为这会导致帧停顿并中断 UI 的响应
In Unity 2020.1 or earlier, Unity also waits for all other pending asynchronous operations to finish, so the delay in execution can be much longer than that required for just the single operation for which you call this method. In Unity 2020.2 or later, the performance impact can be less pronounced, at least when loading assets that have already been downloaded.
译:在 Unity 2020.1 或更早版本中,Unity 还会等待所有其他待处理的异步操作完成,因此执行的延迟可能比您调用此方法的单个操作所需的时间长得多。在 Unity 2020.2 或更高版本中,性能影响可能会较小,至少在加载已经下载的资源时如此
The following example loads a Prefab asset by address, waits for the operation to complete, and then instantiates the Prefab:
译:以下示例通过地址加载 Prefab 资源,等待操作完成,然后实例化 Prefab:
Custom operations
To create a custom operation, extend the AsyncOperationBase class and override its virtual methods.
译:要创建自定义操作,请扩展 AsyncOperationBase 类并重写其虚拟方法
You can pass the derived operation to the ResourceManager.StartOperation method to start the operation and receive an AsyncOperationHandle struct. The ResourceManager registers operations started this way and shows them in the Addressables Event Viewer.
译:您可以将派生操作传递给 ResourceManager.StartOperation 方法以启动操作并接收 AsyncOperationHandle 结构。ResourceManager 会注册以这种方式启动的操作并在 Addressables 事件查看器中显示它们
Executing the operation
The ResourceManager invokes the AsyncOperationBase.Execute method for your custom operation once the optional dependent operation completes.
译:ResourceManager 在可选的依赖操作完成后为您的自定义操作调用 AsyncOperationBase.Execute 方法
Completion handling
When your custom operation completes, call AsyncOperationBase.Complete on your custom operation object. You can call this within the Execute method or defer it to outside the call.
译:当您的自定义操作完成时,请在自定义操作对象上调用 AsyncOperationBase.Complete。您可以在 Execute 方法内部调用它,也可以将其推迟到调用外部
AsyncOperationBase.Complete notifies the ResourceManager that the operation has finished. The ResourceManager invokes the associated AsyncOperationHandle.Completed events for the relevant instances of the custom operation.
译:AsyncOperationBase.Complete 通知 ResourceManager 操作已完成。ResourceManager 为相关自定义操作的 AsyncOperationHandle.Completed 事件调用相应的实例
Terminating the operation
The ResourceManager invokes the AsyncOperationBase.Destroy method for your custom operation when the operation AsyncOperationBase.ReferenceCount reaches zero.
译:当操作 AsyncOperationBase.ReferenceCount 达到零时,ResourceManager 会为您的自定义操作调用 AsyncOperationBase.Destroy 方法
The AsyncOperationBase.ReferenceCount is decreased when the AsyncOperationHandle that references it is released using Addressables.Release or when AsyncOperationBase.DecrementReferenceCount is called by a custom operation internally. AsyncOperationBase.Destroy is where you should release any memory or resources associated with your custom operation.
译:当释放引用它的 AsyncOperationHandle 或自定义操作内部调用 AsyncOperationBase.DecrementReferenceCount 时,AsyncOperationBase.ReferenceCount 会减少。AsyncOperationBase.Destroy 是您释放与自定义操作关联的任何内存或资源的位置
Using typed versus typeless operation handles
Most Addressables methods that start an operation return a generic AsyncOperationHandle<T> struct, allowing type safety for the AsyncOperationHandle.Completed event and for the AsyncOperationHandle.Result object. You can also use a non-generic AsyncOperationHandle struct and convert between the two handle types as desired.
译:大多数 Addressables 启动操作的方法都返回通用的 AsyncOperationHandle 结构,允许为 AsyncOperationHandle.Completed 事件和 AsyncOperationHandle.Result 对象提供类型安全。您还可以使用非泛型的 AsyncOperationHandle 结构并根据需要在两种句柄类型之间进行转换
Note that a runtime exception occurs if you attempt to cast a non-generic handle to a generic handle of an incorrect type. For example:
译:如果您尝试将非泛型句柄转换为不正确类型的泛型句柄,将会引发运行时异常。例如
Reporting operation progress
AsyncOperationHandle has two methods that you can use to monitor and report the progress of the operation:
译:异步操作句柄(AsyncOperationHandle)有两种方法可以用来监视和报告操作的进度
GetDownloadStatus returns a DownloadStatus struct. This struct contains information about how many bytes have been downloaded and how many bytes still need to be downloaded. The DownloadStatus.Percent reports the percentage of bytes downloaded.译:GetDownloadStatus 方法返回一个 DownloadStatus 结构体,该结构体包含已下载的字节数和尚需下载的字节数等信息。DownloadStatus.Percent 属性报告已下载字节数的百分比
AsyncOperationHandle.PercentComplete returns an equally-weighted aggregate percentage of all the sub-operations that are complete. For example, if an operation has five sub-operations, each of them represents 20% of the total. The value doesn't factor in the amount of data that must be downloaded by the individual sub-operations.译:AsyncOperationHandle.PercentComplete 方法返回所有子操作完成的等权重聚合百分比。例如,如果一个操作有五个子操作,每个子操作代表总进度的 20%,该值不考虑每个子操作需要下载的数据量。
For example, if you called Addressables.DownloadDependenciesAsync and five AssetBundles needed to be downloaded, GetDownloadStatus would tell you what percentage of the total number of bytes for all sub-operations had been downloaded so far. PercentComplete would tell you what percentage of the number of operations had finished, regardless of their size.
译:例如,如果您调用 Addressables.DownloadDependenciesAsync,需要下载五个 AssetBundle,则 GetDownloadStatus 方法会告诉您迄今为止已下载了所有子操作的总字节数的百分比。而 PercentComplete 方法会告诉您已完成的操作数的百分比,而不考虑它们的大小
On the other hand, if you called LoadAssetAsync, and one bundle had to be downloaded before an asset could be loaded from it, the download percentage might be misleading. The values obtained from GetDownloadStatus would reach 100% before the operation finished, because the operation had additional sub-operations to conduct. The value of PercentComplete would be 50% when the download sub-operation finished and 100% when the actual load into memory was complete.
译:另一方面,如果您调用 LoadAssetAsync,需要从一个 bundle 中下载资产,下载进度可能会误导。在下载子操作完成之前,从 GetDownloadStatus 方法获得的值将达到 100%,因为操作需要进行其他子操作。而当下载子操作完成时,PercentComplete 的值将为 50%,当实际加载到内存中时,该值将为 100%。在Unity Addressable系统中,用户正在尝试从远程服务器下载预制件并在加载屏幕上报告其下载进度。他们在其协程中使用 while 循环来更新进度条,并尝试在网上寻找解决方案来修复其代码,但没有成功。当单击按钮时,另一个脚本会调用 DownloadAsset 函数。作者希望获得任何提示或建设性的批评来帮助解决他们的问题