包含此页的版本:
不含此页的版本:
NativeContainer是本机内存的线程安全 C# 包装器。NativeContainer对象还允许作业访问与主线程共享的数据,而不是使用副本。
这Unity.Collections命名空间包含以下内置NativeContainer对象:
NativeArray:向托管代码公开本机内存缓冲区的非托管数组NativeSlice:获取NativeArray从特定位置到一定长度。
注意:Collections 包包含额外的NativeContainers.有关其他类型的完整列表,请参阅有关集合类型的集合文档。
默认情况下,当作业有权访问NativeContainer实例,它同时具有读取和写入访问权限。此配置可能会降低性能。这是因为作业系统不允许您计划对NativeContainer实例与写入它的另一个作业同时。
但是,如果作业不需要写入NativeContainer实例中,您可以标记NativeContainer使用[ReadOnly]属性,如下所示:
[ReadOnly]
public NativeArray<int> input;
在上面的示例中,您可以与其他作业同时执行该作业,这些作业对第一个作业也具有只读访问权限NativeArray.
当您创建NativeContainer实例中,必须指定所需的内存分配类型。您使用的分配类型取决于您希望将本机容器保留多长时间。通过这种方式,您可以定制分配,以便在每种情况下获得最佳性能。
有三种分配器类型NativeContainer内存分配和释放。在实例化NativeContainer实例:
Allocator.Temp:最快的分配。将其用于生命周期为一帧或更短的分配。您不能使用Temp将分配传递给NativeContainer实例存储在作业的成员字段中。Allocator.TempJob:分配速度慢于Temp但比Persistent.在四帧的生命周期内将其用于线程安全分配。重要提示:您必须Dispose此分配类型,否则控制台会打印从本机代码生成的警告。大多数小型作业都使用此分配类型。Allocator.Persistent:最慢的分配,但可以持续到您需要的时间,并在必要时持续整个应用程序的生命周期。它是直接调用malloc.较长的作业可以使用此 NativeContainer 分配类型。不要使用Persistent性能至关重要的地方。例如:
NativeArray<float> result = new NativeArray<float>(1, Allocator.TempJob);
注意:上面示例中的数字 1 表示 NativeArray 的大小。在这种情况下,它只有一个数组元素,因为它只在其结果中存储一条数据。
安全系统内置于所有NativeContainer实例。它跟踪读取或写入任何内容NativeContainer实例,并使用该信息来执行有关使用NativeContainers 使它们在多个作业和线程中以确定性的方式行事。
例如,如果两个独立的计划作业写入同一NativeArray,这是不安全的,因为您无法预测哪个作业首先执行。这意味着您将不知道哪些作业将覆盖来自另一个作业的数据。当您计划第二个作业时,安全系统会抛出一个异常,并显示一条明确的错误消息,解释为什么以及如何解决问题。
如果要调度两个写入同一的作业NativeContainer实例中,您可以计划具有依赖项的作业。第一个作业写入NativeContainer,一旦它完成执行,下一个作业就会安全地读取和写入相同的作业NativeContainer.引入依赖关系可保证作业始终以一致的顺序执行,并且NativeContainer是确定性的。
安全系统允许多个作业并行读取相同的数据。
这些读写限制也适用于从主线程访问数据时。例如,如果尝试在写入 NativeContainer 的作业完成之前读取 NativeContainer 的内容,则安全系统会引发错误。同样,如果尝试写入 NativeContainer,而仍有读取或写入的挂起作业,则安全系统也会引发错误。
此外,由于 NativeContainers 没有实现ref return,则不能直接更改NativeContainer.例如nativeArray[0]++;和写作一样var temp = nativeArray[0]; temp++;它不会更新nativeArray.
相反,您必须将数据从索引复制到本地临时副本中,修改该副本,然后将其保存回来。例如:
MyStruct temp = myNativeArray[i];
temp.memberVariable = 0;
myNativeArray[i] = temp;